wpf 在 UserControl 中的 DataTemplate 中指定转换器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20635329/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:14:38  来源:igfitidea点击:

Specify Converter inside DataTemplate in UserControl

c#wpfxaml

提问by Torbj?rn Kalin

I have created a user control that has a Label and a ComboBox. It is used like this:

我创建了一个具有标签和组合框的用户控件。它是这样使用的:

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

And here is what the UserControl XAML looks like:

下面是 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>

In the comment above you can see my problem. The control is generic (the ComboBox can contain pretty much anything) but on the Binding inside the DataTemplate I have specified a Converter that is very specific.

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

How can I specify the Converter from outside the UserControl?

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

I'm hoping for some kind of solution using a dependency property like this:

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

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

回答by Clemens

You may have an internal binding converter that delegates its Convert and ConvertBack calls to one set is settable as dependency property:

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

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

The internal converter could look like this:

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

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

And finally the dependency property code like this:

最后是这样的依赖属性代码:

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

回答by Krishna

You can create multiple datatemplates for the the combobox items and then you can control what and how you want to display your comboxitem like below

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

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

If you do not have multiple viewmodels then you can use a template selector to select different data templates based on some property in your viewmodel.

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

回答by Mashton

EDIT: reworked to not use my personal example to avoid confusion ...

编辑:重新设计以不使用我的个人示例以避免混淆......

On your user control code behind you could define your dependency property.

在你背后的用户控制代码上,你可以定义你的依赖属性。

I don't know what type your converters derive from so change 'myConverterType' to the type of converters you use.

我不知道您的转换器源自什么类型,因此将“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);

In XAML you should then just be able to set the converter property as per your example. In my example it is used like this:

在 XAML 中,您应该能够根据您的示例设置转换器属性。在我的例子中,它是这样使用的:

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

Then use this property, on your user control xaml, like this:

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

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

回答by Torbj?rn Kalin

OP here. Presenting the solution that I'll use until I find something better.

在这里。展示我将使用的解决方案,直到找到更好的解决方案。

I don't specify only the Converter, but the whole DataTemplate:

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

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

And here's the ItemTemplate dependency property:

这是 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); }
    }

    // ...
}