【问题标题】:How do I access the DataContext in from another window?如何从另一个窗口访问 DataContext?
【发布时间】:2019-07-28 12:35:30
【问题描述】:

问题

  1. 当我打开 SecondView 并在 TextBox 和 然后我关闭Window 并重新打开它,那里没有文字 如果它没有被绑定。我相信这是因为我是 每次单击按钮时都会创建View 的新实例 显示SecondView

  2. 我不知道如何访问里面的属性 SecondViewModel 来自我的 MainViewModel,而无需创建 新实例。

我希望能够从SecondViewModel 中的GrabDataFromSecondViewModelCommand 中获取Name 属性

MainView 开始,这就是它的样子。

...
        xmlns:local="clr-namespace:Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <StackPanel>
        <Button Command="{Binding ShowSecondViewCommand}"
                Height="25" Width="100"/>

        <Button Command="{Binding GrabDataFromSecondViewDataContext}"
                Height="25" Width="100"/>
    </StackPanel>

它是DataContext looks like this.

class MainViewModel
    {
        public RelayCommand ShowSecondViewCommand { get; set; }
        public RelayCommand GrabDataFromSecondViewModelCommand { get; set; }

        public MainViewModel()
        {
            ShowSecondViewCommand = new RelayCommand(o =>
            {
                var SecondView = new SecondView();
                SecondView.ShowDialog();
            }, o => true);


            GrabDataFromSecondViewModelCommand = new RelayCommand(o =>
            {
                /*Not sure how to grab the data from SecondViewModel
                 without having to initialize a new instance of it.
                 */

            }, o => true);
        }
    }

SecondView 看起来像这样。

...
        xmlns:local="clr-namespace:Views"
        mc:Ignorable="d"
        Title="SecondView" Height="450" Width="800">
    <Window.DataContext>
        <local:SecondViewModel/>
    </Window.DataContext>

    <Grid>
        <TextBox Text="{Binding Name}"
                 Height="25" Width="100"/>
    </Grid>

它是DataContext,就像这样。

class SecondViewModel : ObservableObject
    {
        public SecondViewModel()
        {

        }

        private string _name;

        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged();
            }
        }

    }

我还不如把RelayCommandObservableObject扔在这里

ObservableObject

类 ObservableObject : INotifyPropertyChanged { 公共事件 PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

}

中继命令

public class RelayCommand : ICommand
    {
        private readonly Func<object, bool> canExecute;
        private readonly Action<object> execute;

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public bool CanExecute(object parameter)
        {
            return canExecute == null || canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            execute(parameter);
        }
    }

更新 所以我改变了 SHowCommand 来做到这一点

ShowSecondViewCommand = new RelayCommand(o =>
            {
                SecondViewModel = new SecondViewModel();
                var SecondView = new SecondView(SecondViewModel);
                SecondView.ShowDialog();
            }, o => true);

然后在SecondView windows 初始化程序列表中,我像这样设置 DataContext

public SecondView(SecondViewModel svm)
        {
            DataContext = svm;
            InitializeComponent();
        }

每次命令打开窗口时都会使用一个新实例。

新更新
现在我明白了

 public SecondViewModel SecondViewModel { get; } = new SecondViewModel();

        public MainViewModel()
        {

            ShowSecondViewCommand = new RelayCommand(o =>
            {
                var SecondView = new SecondView(SecondViewModel);
                SecondView.ShowDialog();
            }, o => true);

它仍然可以编译,但它仍然会创建一个新实例。

【问题讨论】:

  • 不要在 SecondWindow 的 XAML 中分配视图模型。相反,在创建 SecondWindow 实例后传递一个,理想情况下是 MainViewModel 的一个属性,例如var secondView = new SecondView { DataContext = this.SecondViewModel };
  • 所以我会在MainViewModel 中创建一个SecondViewModel 的新实例,然后将该新实例传递给SecondView 窗口构造函数?在 Window 的构造函数内部,我在后面的代码中设置了 DataContext?
  • 那不是构造函数,而是初始化列表。无论如何,您将 MainViewModel 属性的值传递给 SecondView 实例的 DataContext。你什么时候初始化那个属性,我不知道。
  • 因为如果我这样做,它仍然不会保存我在文本框中输入的内容,因为每次打开该窗口时都会传递一个新的空 ViewModel。
  • 一个“新的空视图模型”?你为什么这样做?为什么不初始化一些 SecondViewModel 属性一次并重用它?

标签: c# .net wpf mvvm


【解决方案1】:

使用组合并让您的MainViewModel 引用SecondViewModel。这样你就可以在MainViewModel的范围内直接访问它。创建SecondView 的新实例时(不应由视图模型负责),只需将SecondViewModel 的引用分配给视图DataContext 并从SecondView 中删除参数化构造函数。

class MainViewModel
{
    public SecondViewModel SecondViewModel { get; }
    public RelayCommand ShowSecondViewCommand { get; set; }
    public RelayCommand GrabDataFromSecondViewModelCommand { get; set; }

    public MainViewModel()
    {
        this.SecondViewModel = new SecondViewModel();
        ShowSecondViewCommand = new RelayCommand(o =>
        {
            var SecondView = new SecondView() { DataContext = this.SecondViewModel };
            SecondView.ShowDialog();
        }, o => true);


        GrabDataFromSecondViewModelCommand = new RelayCommand(o =>
        {
            // Directly access the view model
            string valueFromAssociatedViewModel = this.SecondViewModel.Name;
        }, o => true);
    }
}

我认为你的最后一次更新应该可以工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多