2

我正在创建一个应用程序,其工作方式类似于某些 Microsoft 应用程序的“向导”组件。为了表示这一点,我有两个 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 解决方案也受到赞赏。)

4

2 回答 2

2

您的类需要实现INotifyPropertyChanged接口,以在每次其属性之一更改时通知 UI:

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... */
}
于 2012-07-03T11:07:32.853 回答
2

首先,您的视图模型应该实现 INotifyPropertyChanged 或只使用 BindingMode OneTime。(请参阅这篇文章)

不过,您可以使用 viewmodel first 方法和 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; }
}

窗口.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>

每当您在视图模型中设置 CurrentStep 属性时。您将在您的内容控件中看到正确的视图。如果没有,则缺少 DataTemplate ;)

于 2012-07-03T11:21:23.827 回答