首页 > 解决方案 > 如何从另一个窗口访问 DataContext?

问题描述

问题

  1. 当我打开SecondView并在其中键入内容TextBox然后关闭Window并重新打开它时,那里没有文本,好像它没有被绑定一样。我相信这是因为View每次单击显示SecondView

  2. 我不知道如何在 不创建新实例的情况下访问SecondViewModelfrom my中的属性。MainViewModel

我希望能够从内部获得Name财产SecondViewModelGrabDataFromSecondViewModelCommand

从 开始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();
            }
        }

    }

我不妨把RelayCommand&扔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);

然后在SecondViewwindows初始化列表中我像这样设置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);

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

标签: c#.netwpfmvvm

解决方案


使用组合并让您MainViewModelSecondViewModel. 这样你就可以直接从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);
    }
}

我认为您的最后一次更新应该有效。


推荐阅读