在XAML中使用基本控件,但加载派生控件

时间:2014-03-17 17:59:49

标签: wpf

这是我想要解决的问题:

我有一个基本UserControl,我从中导出了许多其他控件,这些控件以特定方式处理基础对象的派生。 (这样做的目的是为了在以后需要额外派生基本控件的时候创建一个模板。)我想要做的是使用基本控件名称作为XAML中的标记,但是当控件实际上是渲染,显示派生控件。

class BaseControl : UserControl { }

class DerivedControl1 : BaseControl { }

class DerivedControl2 : BaseControl { }

class BaseObject { }

class DerivedObject1 : BaseObject { // Requires DerivedControl1 to display }

class DerivedObject2 : BaseObject { // Requires DerivedControl2 to display }

class BaseContainerObject { }

class ContainerObject1 : BaseContainerObject
{
   DerivedObject1 dObject0;
   DerivedObject1 dObject1;
   DerivedObject2 dObject2;
}

class ContainerObject2 : BaseContainerObject
{
   DerivedObject2 dObject0;
   DerivedObject2 dObject1;
   DerivedObject1 dObject2;
}

window.xaml
<!-- Here is what I would like to do -->
<StackPanel>
   <BaseControl Name="Object0" DependencyProperties="{Binding BaseContainerObject.dObject0}" />
   <BaseControl Name="Object1" DependencyProperties="{Binding BaseContainerObject.dObject1}" />
   <BaseControl Name="Object2" DependencyProperties="{Binding BaseContainerObject.dObject2}" />
</StackPanel>

我已经使用样式和数据触发器来检测ContainerObject的特定类型,但我还没有找到将ContainerObject封装在单个模板中的正确模式#34;&#34;包&# 34;然而。

我可以从代码隐藏中动态添加控件,但到目前为止我还没有运气。 (控件的顶级显示在VisualTree上,但树上没有子项,也没有子项呈现。)

有什么想法吗?

编辑:

我目前无法发布截图,但也许我可以添加一些细节。

我有一个数据对象(窗口的DataContext),它有多达九个属性(DerivedObjects),用户需要在我的窗口中编辑它们。这九个属性的含义,以及它们应如何在UI控件中表达,基于用户在上一步中选择的第二个数据对象的属性进行更改。 (这是ContainerObject。上面的代码中没有引用其他数据对象,尽管它包含对第二个数据对象的引用。)

这些属性可以用四种不同的方式表示:文本框(用于连续值),组合框(用于离散值),复选框(用于布尔值)和单选按钮(用于在两个值之间进行选择)。

我创建了UserControls,将这些控件打包在一个水平网格中,其中1)为值定义的标签,2)值的单位(如果适用),以及(如果适用)3)a复选框以备用格式查看值(即以十六进制查看十进制数)。 (这些是DerivedControls,它继承自存储公共属性和函数的无XAML的BaseControl。)为了在整个集合中保持正确的列对齐,我在Window级别的Style中指定了四个列宽,并使用Converter来处理对齐对于不需要单位和/或alt-display复选框的属性。

当用户在上一步中选择第二个对象时,集合控件的九行应该查看DataContext对象的第二个数据对象引用,以选择正确的模板并填充其他标签。因为我需要在其他程序中使用这个集合,所以我在一个单独的程序集中创建它。

我知道我在这方面以某种方式为自己打鸽子。我试图用尽可能少的代码来做这件事,但我不能想到在这里使用正确的代码模式。每个组件都运行正常,但我似乎无法以一种简单的方式将所有组件集合在一起,因此我可以解决最后几个小错误。

感谢。我只是在学习WPF,我真的很喜欢。我正试图让我的脑袋缠绕在一些更精细的细节上。

1 个答案:

答案 0 :(得分:2)

Here is a pretty good example from wpftutorial.net听起来你需要什么。总而言之,您可以使用DataTemplate来定义对象在重复控件(如ListBox,ComboBox或ListView)中的显示方式。您可以覆盖那些样式以使它们按照您的需要显示,或者有时直接使用ItemsControl(它们继承的控件)更容易。它们有一个名为ItemsPanel的属性,允许您将StackPanel指定为ItemsPanelTemplate,这样您就可以获得与上面显示的对象相同的所需布局。

通过DataTemplate设置对象的显示方式很棒,但如果我理解正确,您希望根据绑定对象的类型动态更改该模板。这可以通过创建DataTemplateSelector来实现。

public class PropertyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultDataTemplate { get; set; }
    public DataTemplate DerivedObject1Template { get; set; }
    public DataTemplate DerivedObject2Template { get; set; }

    public override DataTemplate SelectTemplate(object item, 
               DependencyObject container)
    {
        DataTemplate selectedTemplate = DefaultDataTemplate;

        if (item is DerivedObject1)
        {
            selectedTemplate = DerivedObject1Template
        }
        else if (item is DerivedObject2)
        {
            selectedTemplate = DerivedObject2Template;
        }

        return selectedTemplate;
    }
}

然后你的XAML可以在重复控件上使用模板选择器:

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:..."
    xmlns:sys="clr-namespace:System;assembly=mscorlib">

    <Window.Resources>

        <!-- Default DataTemplate -->
        <DataTemplate x:Key="DefaultDataTemplateResource">
           ...
        </DataTemplate>

        <!-- DataTemplate for Booleans -->
        <DataTemplate x:Key="DerivedObject1TemplateResource">
           <local:DerivedControl1 .../>
        </DataTemplate>

        <!-- DataTemplate for Enums -->
        <DataTemplate x:Key="DerivedObject2TemplateResource">
            <local:DerivedControl2 .../>
        </DataTemplate>

        <!-- DataTemplate Selector -->
        <local:PropertyDataTemplateSelector x:Key="myCustomTemplateSelector"
              DefaultnDataTemplate="{StaticResource DefaultDataTemplateResource}"
              DerivedObject1Template = "{StaticResource DerivedObject1TemplateResource}" 
              DerivedObject2Template = "{StaticResource DerivedObject2TemplateResource}"/>
    </Window.Resources>
    <Grid>
        <ItemsControl ItemsSource="{Binding}" ItemTemplateSelector="{StaticResource myCustomTemplateSelector}"/>
    </Grid>
</Window>

希望这会让你开始!