【问题标题】:Unable to get values from pop up window in parent view model WPF MVVM application无法从父视图模型 WPF MVVM 应用程序的弹出窗口中获取值
【发布时间】:2020-06-25 13:47:56
【问题描述】:

我正在尝试从父视图模型访问子窗口视图模型的属性值。我正在从父视图模型调用窗口。我想根据子视图模型中的操作在主窗口中进行更改。我无法在父视图模型中获得子视图模型的任何值。我正在尝试使用 MVVM 模式。

对话界面

 public interface IWindowService
{
    void OpenDialogWindow(DialogViewModel vm);
     
}

父视图模型

 public class FunctionalViewModel : INotifyPropertyChanged
    {
private readonly IWindowService _windowService;
 private string connectionString;

        public string ConnectionString
        {
            get { return connectionString; }
            set
            {
                connectionString = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ConnectionString"));
            }
        }
 public FunctionalViewModel(IWindowService windowService)
        {
           BuildConnectionCommand = new RelayCommand(new Action<object>(BuildConnectionString));
            _windowService = windowService;
        }
   private void BuildConnectionString(object obj)
        {
            MessageBox.Show("will open a window");
            _windowService.OpenDialogWindow(new DialogViewModel());                                  

        }
}

子视图模型

public class DialogViewModel : FunctionalViewModel,INotifyPropertyChanged
    {
        private string textboxsaf;

        public string Textboxsaf
        {
            get { return textboxsaf; }
            set {
                textboxsaf = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Textboxsaf"));
            }
        }

        private ICommand connectionCommand;

        public ICommand ConnectionCommand
        {
            get { return connectionCommand; }
            set { connectionCommand = value; }

        }
        public DialogViewModel()
        {
            
            ConnectionCommand = new RelayCommand(new Action<object>(SetValue));
            

        }
        public event PropertyChangedEventHandler PropertyChanged;


        public void SetValue(object test)
        {
            textboxsaf= "ValueFromPopUpWindo";           
            Application.Current.Windows[1].Close();
            
        }
     

        }

ChildWindow.xaml

    <Grid>
        <Label x:Name="label" Content="my popup window" HorizontalAlignment="Left" Margin="73,68,0,0" VerticalAlignment="Top" Width="132"/>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="73,121,0,0" 
                 TextWrapping="Wrap" 
                 Text="{Binding Path=Textboxsaf,Mode=TwoWay}" VerticalAlignment="Top" Width="120"/>
        <Button x:Name="button" Content="Button" HorizontalAlignment="Left"
                Margin="109,177,0,0" VerticalAlignment="Top" Width="75"
                 Command="{Binding Path=ConnectionCommand }"
                 />

    </Grid>
</Window>

MainWindow.xaml

<Grid>
 <Button Name="btnConnectionString" Grid.Row="0" Grid.Column="2" Content="Connection string" Height="40" Width="150"
                                 Command="{Binding Path=BuildConnectionCommand}"
                                        DataContext="{Binding tfs}"></Button>
</Grid>

主窗口的代码隐藏文件 MainWindow.xaml.cs

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainViewModel()
            {
                rel = new ReleaseViewModel(),
                tfs =  new FunctionalViewModel(new WindowService()),
                wnd = new DialogViewModel()
            };

        }

  
    }
    public class WindowService : IWindowService
    {
        public void OpenDialogWindow(DialogViewModel vm)
        {
            ConnectionWindow win = new ConnectionWindow();
            win.DataContext = vm;            
            win.Show();            
        }               
    }

问题

我想从父视图模型(FunctionalViewModel) 访问子视图模型(DialogViewModel) 中属性 Textboxsaf 的值。从 funcitonalviewModel 将 Textboxsaf 的值分配给 ConnectionString。关窗后就好了。

【问题讨论】:

    标签: c# wpf xaml mvvm viewmodel


    【解决方案1】:

    我不会使用PropertyChanged 来检索DialogViewModel.Textboxsaf 的值,因为此属性可能会在对话框的生命周期内多次更改。

    我会让IWindowService.OpenDialogWindow 返回一个自定义DialogResult 对象或原始DialogViewModel 可能将IWindowService.OpenDialogWindow 转换为异步方法。

    或者实现一个IWindowService.DialogClosed事件:

    FunctionalViewModel.cs

    public class FunctionalViewModel : INotifyPropertyChanged
    {
        private readonly IWindowService _windowService;
        private string connectionString;
    
        public string ConnectionString
        {
            get { return connectionString; }
            set
            {
                connectionString = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.ConnectionString)));
            }
        }
    
        private void BuildConnectionString(object obj)
        {
            MessageBox.Show("will open a window");
            _windowService.DialogClosed += OnDialogClosed;
            _windowService.OpenDialogWindow(new DialogViewModel());                                  
        }
    
        private void OnDialogClosed(object sender,  DialogResultEventArgs e)
        {
            _windowService.DialogClosed -= OnDialogClosed;
            ConnectionString = e.Result.Textboxsaf;
        }
    }
    

    WindowService.cs

    public class WindowService : IWindowService
    {
        public event EventHandler<DialogResultEventArgs> DialogClosed;
        public void OpenDialogWindow(DialogViewModel vm)
        {
            ConnectionWindow win = new ConnectionWindow();
            win.DataContext = vm;
            win.Closed += OnConnectionWindowClosed;
            win.Show();            
        } 
              
        protected virtual void OnConnectionWindowClosed(object sender, EventArgs e)
        {
            var dialog = sender as FrameworkElement;
            this.DialogClosed?.Invoke(this, new DialogResultEventArgs(dialog.DataContext as DialogViewModel));
        }               
    }
    

    DialogResultEventArgs.cs

    public class DialogResultEventArgs : EventArgs
    {
        public DialogViewModel Result { get; }
              
        public DialogResultEventArgs(DialogViewModel result) => this.Result = result;
    }
    

    【讨论】:

    • @sagartech 此语法是 expression-bodied 构造函数,可从 C# 7.0 获得。似乎您使用的是 public DialogResultEventArgs(DialogViewModel result) { this.Result = result; }。现在应该可以编译了。
    • 不抱歉,我的代码中有错字。我已经修好了..对不起!
    • OnDialogClosed 应该仅在引发 ConnectionWindow.Closed 事件时调用。 ConnectionWindow 有关闭活动吗?我只是假设它是Window。当用户或以编程方式关闭此窗口时,应调用WindowService.OnConnectionWindowClosed。会发生这种情况吗?
    • 这是一个非常非常简单的流程。发现这个简单的错误一定很容易,所以不用担心。 ConnectionWindow 必须有一个 Closed 事件,并且在 ConnectionWindow 关闭时引发此事件。如果没有调用 WindowService.OnConnectionWindowClosed,则检查是否调用了 ConnectionWindow.Closed。
    • 啊,看到了吗?没有Closed 事件,没有DialogClosed 事件。您不需要重复使用该窗口。关闭它。但是如果重用实例对您有用,那么在将Visibility 设置为Hidden 时,只需在ConnectionWindow 内调用OnClosed(EventArgs.Empty);。这只会引发Window.Closed 事件,而不会实际关闭窗口。这应该是最后的修复。不知道您正在重用ConnectionWindow 实例。
    【解决方案2】:

    您可以保留对DialogViewModel 的引用并订阅其PropertyChanged 事件:

    private void BuildConnectionString(object obj)
    {
        var childViewModel = new DialogViewModel();
        childViewModel.PropertyChanged += OnChildPropertyChanged;
        MessageBox.Show("will open a window");
        _windowService.OpenDialogWindow(childViewModel);
    }
    
    private void OnChildPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(DialogViewModel.Textboxsaf))
        {
            childViewModel.PropertyChanged -= OnChildPropertyChanged;
            ConnectionString = (sender as DialogViewModel)?.DialogViewModel;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-23
      • 2010-10-12
      • 1970-01-01
      • 2018-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多