2016-03-08 66 views
1

我有一个MVVM WPF应用程序,用于显示纸牌游戏的卡片。我只是将它们显示在屏幕上,但是对于许多卡片,它们都在可观察的集合中。但是,卡片都是不同的类型,它们都是从一个基类继承而来的。每种卡片类型与用户控件都有自己完全不同的视图。因此,根据我的经验,我明白我可以将ItemSource属性绑定到可观察集合,但是如何根据我的ItemSource中的项目类型指定使用某些用户控件?我推理我可以加载所有用户控制卡,并根据卡类型在转换器中打开或关闭每个控制器的可见性,但这听起来对我来说效率极低。任何人有任何想法?如何在XAML WPF窗口中使用动态元素

+0

您声明每种卡类型的[DataTemplate](https://msdn.microsoft.com/library/ms742521(v = vs.100).aspx)。或者,如果卡片的类型都是相同的,但是在属性中指定了它们的类型,则可以使用[DataTriggers](http://www.wpf-tutorial.com/styles/trigger-datatrigger-event-trigger/)。 –

回答

2

您正在寻找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(或列表框,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的位置取决于您,但只要它位于控件的资源层次结构中,就会使用它。

1

用于映射UI创建ResourceDictionary(EI地图视图模型模型),并将其注册

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; 
     } 
    } 
} 

观察集合然后换为ObservableCollection<BaseClass>,所选视图将显示派生类视图。

+0

对于SO的要求,这似乎太过分了。他们不需要在自己的ResourceDictionary中,即使他们不需要将它合并到代码中,也可以将其添加到应用程序xaml中。 –

+0

嗨马克,当然,你是对的,解决方案只需要'将ViewModel匹配到视图',但我仍然认为最优雅,有序和可维护的解决方案就是我的回答。 –

+0

感谢您对这个答案的输入!虽然我确实喜欢这个解决方案的简单性,但是这个项目并没有创建/处理资源字典的能力。这有点奇怪,但是团队中的每个成员都具有某些他们可以做的事情,并且创建一个全球资源字典对于这个项目来说是不可能的。 – Chris