具有依赖属性的值转换器

发布于 2024-11-26 21:14:11 字数 3447 浏览 0 评论 0原文

我在实现自定义 DependencyObject 时遇到问题:

我需要一个转换器来设置或取消设置绑定属性中的枚举标志。因此,我创建了一个从 FrameworkElement 派生的 IValueConverter,它具有两个 DependencyProperties:Flag(由转换器设置/取消设置的标志)和 Flags(要修改的值/属性)。父 UserControl(名称 = EnumerationEditor)提供转换器绑定到的属性。

ListBox 生成复选框和转换器实例,用于通过 DataTemplate 修改属性。每个复选框/转换器实例都用于一个标志。我使用以下 XAML 代码:

<ListBox Name="Values" SelectionMode="Extended" BorderThickness="1" BorderBrush="Black" Padding="5">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="{x:Type system:Enum}">

            <DataTemplate.Resources>
                <Label x:Key="myTestResource" x:Shared="False"
                            Content="{Binding}"
                            ToolTip="{Binding Path=Value, ElementName=EnumerationEditor}"
                            Foreground="{Binding Path=Background, ElementName=EnumerationEditor}"
                            Background="{Binding Path=Foreground, ElementName=EnumerationEditor}"/>
                <converters:EnumerationConverter x:Key="EnumerationConverter" x:Shared="False"
                                                    Flag="{Binding}"
                                                    Flags="{Binding Path=Value, ElementName=EnumerationEditor}"/>
            </DataTemplate.Resources>

            <StackPanel Orientation="Horizontal">
                <CheckBox Content="{Binding}" IsChecked="{Binding Path=Value, ElementName=EnumerationEditor, Converter={StaticResource EnumerationConverter}}"/>
                <ContentPresenter Content="{StaticResource myTestResource}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

奇怪的事情:标签工作正常 - 但转换器却不能。我收到错误:

System.Windows.Data 错误:4:找不到引用“ElementName=EnumerationEditor”的绑定源。绑定表达式:路径=值;数据项=空;目标元素是“EnumerationConverter”(名称=“”);目标属性是“Flags”(类型“Enum”)

我不明白为什么,绑定基本上是相同的......

这是转换器的代码:

public class EnumerationConverter : FrameworkElement, IValueConverter
{

    #region IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Parity.Space;
    }

    #endregion

    #region public Enum Flag { get; set; }

    public Enum Flag
    {
        get { return (Enum)this.GetValue(EnumerationConverter.FlagProperty); }
        set { this.SetValue(EnumerationConverter.FlagProperty, value); }
    }

    /// <summary>
    /// Dependency property for Flag.
    /// </summary>
    public static readonly DependencyProperty FlagProperty = DependencyProperty.Register("Flag", typeof(Enum), typeof(EnumerationConverter));

    #endregion

    #region public Enum Flags { get; set; }

    public Enum Flags
    {
        get { return (Enum)this.GetValue(EnumerationConverter.FlagsProperty); }
        set { this.SetValue(EnumerationConverter.FlagsProperty, value); }
    }

    /// <summary>
    /// Dependency property for Flags.
    /// </summary>
    public static readonly DependencyProperty FlagsProperty = DependencyProperty.Register("Flags", typeof(Enum), typeof(EnumerationConverter));

    #endregion

}

I have problems implementing a custom DependencyObject:

I need a converter which sets or unsets a enum flag in a bound property. Therefore I created a IValueConverter derieved from FrameworkElement with two DependencyProperties: Flag (the flag which is set/unset by the converter) and Flags (the value/property to modify). The parent UserControl (Name = EnumerationEditor) provides the property to which the converter is bound.

A ListBox generates CheckBoxes and the converter instances which are used to modify the property via a DataTemplate. Each CheckBox/converter instance is used for one flag. I use the following XAML code:

<ListBox Name="Values" SelectionMode="Extended" BorderThickness="1" BorderBrush="Black" Padding="5">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="{x:Type system:Enum}">

            <DataTemplate.Resources>
                <Label x:Key="myTestResource" x:Shared="False"
                            Content="{Binding}"
                            ToolTip="{Binding Path=Value, ElementName=EnumerationEditor}"
                            Foreground="{Binding Path=Background, ElementName=EnumerationEditor}"
                            Background="{Binding Path=Foreground, ElementName=EnumerationEditor}"/>
                <converters:EnumerationConverter x:Key="EnumerationConverter" x:Shared="False"
                                                    Flag="{Binding}"
                                                    Flags="{Binding Path=Value, ElementName=EnumerationEditor}"/>
            </DataTemplate.Resources>

            <StackPanel Orientation="Horizontal">
                <CheckBox Content="{Binding}" IsChecked="{Binding Path=Value, ElementName=EnumerationEditor, Converter={StaticResource EnumerationConverter}}"/>
                <ContentPresenter Content="{StaticResource myTestResource}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

The strange thing: The Label works fine - but the converter does not. I get the error:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=EnumerationEditor'. BindingExpression:Path=Value; DataItem=null; target element is 'EnumerationConverter' (Name=''); target property is 'Flags' (type 'Enum')

I don't understand why, the binding is basically the same...

Here is the code for the converter:

public class EnumerationConverter : FrameworkElement, IValueConverter
{

    #region IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Parity.Space;
    }

    #endregion

    #region public Enum Flag { get; set; }

    public Enum Flag
    {
        get { return (Enum)this.GetValue(EnumerationConverter.FlagProperty); }
        set { this.SetValue(EnumerationConverter.FlagProperty, value); }
    }

    /// <summary>
    /// Dependency property for Flag.
    /// </summary>
    public static readonly DependencyProperty FlagProperty = DependencyProperty.Register("Flag", typeof(Enum), typeof(EnumerationConverter));

    #endregion

    #region public Enum Flags { get; set; }

    public Enum Flags
    {
        get { return (Enum)this.GetValue(EnumerationConverter.FlagsProperty); }
        set { this.SetValue(EnumerationConverter.FlagsProperty, value); }
    }

    /// <summary>
    /// Dependency property for Flags.
    /// </summary>
    public static readonly DependencyProperty FlagsProperty = DependencyProperty.Register("Flags", typeof(Enum), typeof(EnumerationConverter));

    #endregion

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

辞慾 2024-12-03 21:14:11

转换器不是 FrameworkElement,因此它不应该从该类继承,最好使用 DependencyObject

由于转换器不在任何绑定不起作用的树中,您可以尝试:(

<converters:EnumerationConverter x:Key="EnumerationConverter" x:Shared="False"
                                 Flag="{Binding}"
                                 Flags="{Binding Path=Value, Source={x:Reference EnumerationEditor}}"/>

但是,这应该放置在 UserControlResources 中并引用,否则< a href="http://msdn.microsoft.com/en-us/library/ee795380.aspx" rel="noreferrer">x:Reference 将导致循环依赖错误。)

笔记Flag 绑定尝试绑定到 DataContext,这可能不起作用,因为 DataContext 可能无法继承,原因与 ElementNameRelativeSource 将不起作用。

A converter is not a FrameworkElement so it should not inherit from that class, at best use DependencyObject.

Since the converter is not in any tree that binding will not work, you can try:

<converters:EnumerationConverter x:Key="EnumerationConverter" x:Shared="False"
                                 Flag="{Binding}"
                                 Flags="{Binding Path=Value, Source={x:Reference EnumerationEditor}}"/>

(However this should be placed in the Resources of the UserControl and referenced, otherwise the x:Reference will cause a cyclical dependency error.)

Note that the Flag binding tries to bind to the DataContext which might not work as the DataContext may not be inherited for the same reasons that ElementName and RelativeSource will not work.

听你说爱我 2024-12-03 21:14:11

结论

我决定使用两个 UserControl 来解决问题; FlagControl 和 EnumerationEditorControl。

FlagControl 有两个依赖属性

  • Flag (System.Enum):确定控件设置/清除哪个标志
  • Value(System.Enum):绑定到设置/清除标志的属性/值。

EnumerationEditorControl 有一个依赖属性:

  • Value(System.Enum):设置标志的属性/值。

EnumerationEditorControl 使用 DataTemplate 来实例化 FlagControls。 DataTemplate 将 FlagControl.Flag 属性绑定到 DataContext,并将 FlagControl.Value 属性绑定到 EnumerationEditorControl.Value 属性。

这样我就不需要转换器,并且逻辑清晰分离。

感谢您的建议、评论和回复!

Conclusion

I decided to solve the problem using two UserControls; FlagControl and EnumerationEditorControl.

The FlagControl has two dependency properties

  • Flag (System.Enum): Determines which flag is set/cleared by the control
  • Value(System.Enum): Bound to the propery/value in which the flag is set/cleared.

The EnumerationEditorControl has one dependency property:

  • Value(System.Enum): The propery/value in which flags are set.

The EnumerationEditorControl uses a DataTemplate to instantiate FlagControls. The DataTemplate binds the FlagControl.Flag property to the DataContext and the FlagControl.Value property to the EnumerationEditorControl.Value property.

This way I don't need a converter and logic is clearly separated.

Thanks for the suggestions, comments and replies!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文