在UserControl中的DataTemplate中指定Converter

时间:2013-12-17 13:22:56

标签: c# wpf xaml

我创建了一个具有Label和ComboBox的用户控件。它的使用方式如下:

<cc:LabeledComboBox
    HeaderLabelContent="Months"
    ItemsSource="{Binding AllMonths}"
    SelectedValue="{Binding SelectedMonth}"/>

以下是UserControl XAML的样子:

<UserControl x:Class="CustomControls.LabeledComboBox" ...>
    <UserControl.Resources>
        <converters:MonthEnumToTextConverter x:Key="MonthEnumToTextConverter" />
    </UserControl.Resources>
    <DockPanel>
        <Label x:Name="LblValue" DockPanel.Dock="Top"/>
        <ComboBox x:Name="LstItems">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <!-- TODO: Fix so that the Converter can be set from outside -->
                    <TextBlock Text="{Binding Converter={StaticResource MonthEnumToTextConverter}}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </DockPanel>
</UserControl>

在上面的评论中,您可以看到我的问题。控件是通用的(ComboBox几乎可以包含任何东西)但是在DataTemplate内部的Binding中我指定了一个非常具体的转换器。

如何从UserControl外部指定转换器?

我希望使用像这样的依赖属性的某种解决方案:

<cc:LabeledComboBox
    ...
    ItemConverter="{StaticResource MonthEnumToTextConverter}"/>

4 个答案:

答案 0 :(得分:2)

您可能有一个内部绑定转换器,它将其Convert和ConvertBack调用委托给一个set可设置为依赖属性:

<UserControl ...>
    <UserControl.Resources>
        <local:InternalItemConverter x:Key="InternalItemConverter"/>
    </UserControl.Resources>
    <DockPanel>
        ...
        <ComboBox>
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding
                        Converter={StaticResource InternalItemConverter}}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </DockPanel>
</UserControl>

内部转换器可能如下所示:

class InternalItemConverter : IValueConverter
{
    public LabeledComboBox LabeledComboBox { get; set; }

    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (LabeledComboBox != null && LabeledComboBox.ItemConverter != null)
        {
            value = LabeledComboBox.ItemConverter.Convert(
                value, targetType, parameter, culture);
        }

        return value;
    }

    public object ConvertBack(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (LabeledComboBox != null && LabeledComboBox.ItemConverter != null)
        {
            value = LabeledComboBox.ItemConverter.ConvertBack(
                value, targetType, parameter, culture);
        }

        return value;
    }
}

最后依赖属性代码如下:

public partial class LabeledComboBox : UserControl
{
    private static readonly DependencyProperty ItemConverterProperty =
        DependencyProperty.Register(
            "ItemConverter", typeof(IValueConverter), typeof(LabeledComboBox));

    public IValueConverter ItemConverter
    {
        get { return (IValueConverter)GetValue(ItemConverterProperty); }
        set { SetValue(ItemConverterProperty, value); }
    }

    public LabeledComboBox()
    {
        InitializeComponent();

        var converter = (InternalItemConverter)Resources["InternalItemConverter"];
        converter.LabeledComboBox = this;
    }
}

答案 1 :(得分:1)

您可以为组合框项目创建多个数据模板,然后您可以控制显示您的comboxitem的内容和方式,如下所示

<DataTemplate DataType="{x:Type vm:MonthDataTypeViewModel}" >
<TextBlock Text="{Binding Converter={StaticResource MonthEnumToTextConverter}}"/>
</DataTemplate>
<DataTemplate DataType={x:Type vm:OtherViewModel}">
<TextBlock Text="{Binding}"/>
</DataTemplate>

如果您没有多个视图模型,则可以使用模板选择器根据视图模型中的某些属性选择不同的数据模板。

答案 2 :(得分:0)

编辑:重新设计,不要使用我个人的例子来避免混淆......

在您的用户控制代码后面,您可以定义您的依赖项属性。

我不知道您的转换器从哪种类型派生,因此将'myConverterType'更改为您使用的转换器类型。

public bool ItemConverter
{
    get { return (myConverterType)GetValue(IntemConverterProperty); }
    set { SetValue(ItemConverterProperty, value); }
}

public static readonly DependencyProperty ItemConverterProperty = 
    DependencyProperty.Register("ItemConverter", typeof(myConverterType), 
    typeof(LabeledComboBox), null);

在XAML中,您应该只能根据示例设置转换器属性。在我的例子中,它使用如下:

<cc:LabeledComboBox ItemConverter="{StaticResource theSpecificConverter}"/>

然后在您的用户控件xaml上使用此属性,如下所示:

<ComboBox x:Name="LstItems">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={Binding ItemConverter, ElementName=UserControl}}"/>
         </DataTemplate>
     </ComboBox.ItemTemplate>
</ComboBox>

答案 3 :(得分:0)

OP在这里。提出我将使用的解决方案,直到找到更好的东西。

我不仅指定转换器,而是指定整个DataTemplate:

<cc:LabeledComboBox>
    <cc:LabeledComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource MonthEnumToTextConverter}}"/>
        </DataTemplate>
    </cc:LabeledComboBox.ItemTemplate>
</cc:LabeledComboBox>

这是ItemTemplate依赖属性:

public partial class LabeledComboBox : UserControl
{
    public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
        "ItemTemplate",
        typeof(DataTemplate),
        typeof(LabeledComboBox),
        new PropertyMetadata(default(DataTemplate), ItemTemplateChanged));

    private static void ItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var labeledComboBox = (LabeledComboBox)d;
        labeledComboBox.LstItems.ItemTemplate = (DataTemplate)e.NewValue;
    }

    public DataTemplate ItemTemplate
    {
        get { return (DataTemplate)GetValue(ItemTemplateProperty); }
        set { SetValue(ItemTemplateProperty, value); }
    }

    // ...
}