我正在创建一个类似于某些微软应用程序的“向导”组件的应用程序。为了表示这一点,我有两个ViewModel:
class WizardVm {
public string Name { get; set; }
public ICommand QuitCommand { get { /* ommitted */ } }
public WizardStepVm CurrentStep { get; set; }
}
class WizardStepVm {
public string StepName { get; set; }
public string StepText {get; set; }
}
在视图中,WizardVm
绑定到窗口,WizardStepVm
绑定到窗口内的内容面板。我以编程方式创建内容控件,并将其添加到WizardView,如下所示:
// in the "DataContextChanged" handler for the WizardView
var bn = new Binding("CurrentStep");
bn.Mode = BindingMode.OneWay;
var contentControl = new ContentControl();
contentControl.SetBinding(ContentControl.ContentProperty, bn);
WizardViewStackPanel.Children.Add(contentControl);
最初创建WizardView时,这会正确呈现。但是,如果CurrentStep
发生更改,则视图不会更新以反映此情况。 CurrentStep更改,但ContentControl继续显示原始WizardStepVm。此外,旧的WizardStepVm继续存在于内存中,其字符串属性仍然可以更改(从视图中)。
这是为什么?我该怎么做才能让内容控件发生变化以反映它绑定的ViewModel中的变化?
(实际上有一个很好的理由以编程方式执行此操作。但是,xaml解决方案也很受欢迎。)
答案 0 :(得分:2)
您的课程需要实现INotifyPropertyChanged界面,以便每次都通知用户界面 其中一个属性发生了变化:
class WizardStepVm : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private string m_stepName;
public string StepName {
get {
return m_stepName;
}
set {
m_stepName = value;
NotifyPropertyChanged("StepName");
}
}
/* etc... */
}
答案 1 :(得分:2)
首先你的viewmodel应该实现INotifyPropertyChanged或者只使用BindingMode OneTime。(见this post)
尽管如此,您可以使用viewmodel first approach和datatemplates
轻松完成您想要的任务public class WizardVm {
public string Name { get; set; }
public ICommand QuitCommand { get { /* ommitted */ } }
public object CurrentStep { get; set; }//raise OnPropertyChanged("CurrentStep"); in your setter!!
}
public class WizardStep1Vm {
public string StepName { get; set; }
public string StepText {get; set; }
}
public class WizardStep2Vm {
public string StepName { get; set; }
public string StepText {get; set; }
}
window.xaml
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type local:WizardStep1Vm}">
<!--your view for step1 goes here-->
<local:MyStep1View/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:WizardStep2Vm}">
<!--your view for step2 goes here-->
<local:MyStep2View/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Name}" />
<ContentPresenter Content="{Binding CurrentStep}"/>
</Grid>
</Window>
何时在viewmodel中设置CurrentStep属性。您将在contentcontrol中看到正确的视图。如果没有,则缺少DataTemplate;)