如何在 XAML WPF window 中包含动态元素

How do I have dynamic elements in a XAML WPF window

我有一个 MVVM WPF 应用程序,我在其中显示纸牌游戏的纸牌。我只是在屏幕上显示它们,连续 4 张卡片,因为可观察的集合中有很多卡片。但是,这些卡都是从一个基础 class 继承而来的所有不同类型。作为用户控件,每种卡片类型都有自己截然不同的视图。因此,根据我的经验,我知道我可以将 ItemSource 属性 绑定到我的可观察集合,但是我如何根据 ItemSource 中的项目类型指定使用某些用户控件?我推测我可以为每张卡加载所有用户控件,并根据卡类型在转换器中打开或关闭每个控件的可见性,但这对我来说效率极低。有人知道吗?

创建一个 ResourceDictionary 用于映射 UI(e.i 将视图模型映射到模型)并注册它

XAML

<ResourceDictionary .....
                    xmlns:views="clr-namespace:...."
                    xmlns:viewModels="clr-namespace:...."
                    >

    <DataTemplate DataType="{x:Type viewModels:viewModels1}">
        <views:view1 />
    </DataTemplate>

    <DataTemplate DataType="{x:Type viewModels:viewModels2}">
        <views:view2 />
    </DataTemplate>

    ...

</ResourceDictionary>

C#

public static class ViewsMapping
{
    private static bool _isUIMappingRegistered = false;

    public static void Register()
    {
        if (!_isUIMappingRegistered)
        {
            ResourceDictionary MyResourceDictionary = new ResourceDictionary();
            MyResourceDictionary.Source = new Uri(".....", UriKind.Relative);
            Application.Current.Resources.MergedDictionaries.Add(MyResourceDictionary);
            _isUIMappingRegistered = true;
        }
    }
}

然后将 observable collection 更改为 ObservableCollection<BaseClass>,所选视图将呈现派生的 class 视图。

您正在寻找 DataTemplates。例如,假设您有以下 类:

public class MyViewModel
{
  public List<PersonInfo> DataItems { get; }
    = new List<PersonInfo>()
      {
        new AgeInfo() { Age = 25 },
        new NameInfo() { Name = 13 }
      };
}

public abstract class PersonInfo
{
}

public class AgeInfo : PersonInfo
{
  public int Age { get; set; }
}

public class NameInfo : PersonInfo
{
  public int Name { get; set; }
}

您可以拥有一个根据项目的数据类型显示每个项目的 ItemsControl(或 ListBox、ListView 等):

<ItemsControl ItemsSource="{Binding DataItems}">
  <ItemsControl.Resources>

    <!-- Names are edited via textboxes -->
    <DataTemplate DataType="{x:Type local:NameInfo}">
      <StackPanel>
        <Label>Name:</Label>
        <TextBox Text="{Binding Name}" />
      </StackPanel>
    </DataTemplate>

    <!-- Ages are edited via slider -->
    <DataTemplate DataType="{x:Type local:AgeInfo}">
      <StackPanel>
        <Label>Age:</Label>
        <Slider Minimum="0" Maximum="150" Value="{Binding Age}" />
      </StackPanel>
    </DataTemplate>

  </ItemsControl.Resources>
</ItemsControl>

放置 DataTemplate 的位置由您决定,但只要它在控件的资源层次结构中,就会使用它。