【发布时间】:2019-07-28 12:35:30
【问题描述】:
问题
当我打开
SecondView并在TextBox和 然后我关闭Window并重新打开它,那里没有文字 如果它没有被绑定。我相信这是因为我是 每次单击按钮时都会创建View的新实例 显示SecondView我不知道如何访问里面的属性
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();
}
}
}
我还不如把RelayCommand和ObservableObject扔在这里
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 属性一次并重用它?