在 UI 中显示来自 ViewModel 的控件

Show Control from ViewModel in UI

我的 ViewModel 中有一个 UserControl,需要根据 ViewModel 的上下文进行更改。

例如:我的 ViewModel 包含一个枚举。当此枚举的值为 Test1 时,CurrentView 属性 将更改为类型 MyCustomTest1 的对象。当值为 Test2 时,属性 成为 MyCustomTest2 的对象。我已经知道如何实现它,但不知道如何告诉我的 UI 呈现 CustomControl。

我想我需要为此使用 ItemsControl,但我不确定。这是我到目前为止尝试过的。

<StackPanel x:Name="MainContent" Grid.Column="1">
        <ItemsControl ItemsSource="{Binding CurrentView, Mode=OneWay}" />
    </StackPanel>

我的自定义组件只包含一个带有 TextBlock 的 StackPanel。

MyCustomTest1:

<StackPanel>
   <TextBlock>Hello World</TextBlock>
</StackPanel>

我的 ViewModel 在更新 CurrentView 时调用 INotifyPropertyChanged。

public UserControl CurrentView 
        { 
            get => currentView;
            private set
            {
                currentView = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentView)));
            }
        }

有人知道如何实现吗?

您可以设计一个 ValueConverter,例如:


using System;
using System.Globalization;
using System.Windows.Data;

public class MyValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(value is ControlType type)
        {
            if (type == ControlType.Type1)
                return new MyCustomTest1();
            else if (type == ControlType.Type2)
                return new MyCustomTest2();
        }
        throw new NotImplementedException();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

然后你可以添加一个ContentControl,并将其Content绑定到枚举属性,并引入转换器:

<UserControl.Resources>
    <!-- vc is the namespace where you put the value converter class -->
    <vc:MyValueConverter x:Key="converter" />
</UserControl.Resources>
...
<ContentControl Content="{Binding CurrentView, Converter={StaticResource converter}}" />

视图模型绝不能知道任何控件。控件仅在视图中处理。

您的问题通常通过使用数据模型和关联的 DataTemplated 来解决,它指示视图如何呈现数据模型。

这意味着您应该为每个视图引入一个数据模型。然后将这个模型绑定到一个ContentControl。然后 ContentControl 将应用 DataTemplate 作为模型的数据类型,然后将呈现视图。

MainViewModel.cs

class MainViewModel : INotifyPropertyChanged
{
  // TODO::Let this property raise the PropertyChanged event
  public object CurrentViewModel { get; set; }

  private void LoadView()
  {
    this.CurrentView = new MyCustomControlViewModel();
  }
}

MainWindow.xaml

<Window>
  <Window.DataContext>
    <MainViewModel />
  </Window.Resources>

  <Window.Resources>
    <DataTemplate DataType="{x:Type MyCustomControlViewModel}">
      <MyCustomControl />
    </DataTemplate>
  </Window.Resources>

  <ContentControl Content="{Binding CurrentViewModel}" />
</Window>