C# 依赖项属性不起作用(生成复合行为)

C# 依赖项属性不起作用(生成复合行为),c#,wpf,dependency-properties,C#,Wpf,Dependency Properties,我试图创建一个由任意简单行为组成的复合行为。我发现定制控件的方式非常灵活 目前我为slider实现了5种行为。但它们可以相互冲突 这些行为是为一个控件设计的。我可以设计它们中的每一个独立工作,而不会相互冲突(值得一提的是,我做到了这一点,并且成功地工作了。但我删除了所有这些,因为它太难看了。) 有很多共享点,我不想为每个行为重写相同的代码 所以我尝试为一个控件创建一个复合行为。此行为具有一些附加属性,这些属性为其所有包含行为共享。因此,这些行为不会相互冲突。而且很多代码冗余也消失了。现在包含行为

我试图创建一个由任意简单行为组成的复合行为。我发现定制控件的方式非常灵活

目前我为slider实现了5种行为。但它们可以相互冲突

这些行为是为一个控件设计的。我可以设计它们中的每一个独立工作,而不会相互冲突(值得一提的是,我做到了这一点,并且成功地工作了。但我删除了所有这些,因为它太难看了。)

有很多共享点,我不想为每个行为重写相同的代码

所以我尝试为一个控件创建一个复合行为。此行为具有一些附加属性,这些属性为其所有包含行为共享。因此,这些行为不会相互冲突。而且很多代码冗余也消失了。现在包含行为变得简单多了

这是XAML示例,您可以更好地了解这一点

<i:Interaction.Behaviors>
    <b:SliderCompositeBehavior SourceValue="{Binding SharedValue}">
        <sb:FreeSlideBehavior/>
        <sb:LockOnDragBehavior/>
        <sb:CancellableDragBehavior/>
        <sb:KeepRatioBehavior/>
        <sb:DragCompletedCommandBehavior Command="{Binding SeekTo}"/>
    </b:SliderCompositeBehavior>
</i:Interaction.Behaviors>

此外,所有这些行为都是为独立工作而设计的。i、 e这样说很好

<i:Interaction.Behaviors>
    <sb:FreeSlideBehavior/>
</i:Interaction.Behaviors>

下面是
合成行为:行为

[ContentProperty(nameof(BehaviorCollection))]
公共抽象类CompositeBhavior:行为
其中T:DependencyObject
{
公共静态只读DependencyProperty BehaviorCollectionProperty=
从属属性。寄存器(
$“{nameof(CompositeBehavior)}”,
类型(可观测采集),
类型(复合行为),
新框架属性元数据(
无效的
FrameworkPropertyMetadataOptions.NotDataBindable));
公共观察收集行为收集
{
得到
{
var collection=GetValue(BehaviorCollectionProperty)作为ObservableCollection;
if(集合==null)
{
集合=新的ObservableCollection();
collection.CollectionChanged+=OnCollectionChanged;
SetValue(BehaviorCollectionProperty,集合);
}
回收;
}
}
CollectionChanged的私有void(对象发送方,NotifyCollectionChangedEventArgs)
{
//某些代码在多次设置相同行为时引发异常。
}
受保护的覆盖无效附加()
{
foreach(BehaviorCollection中的var行为)
{
行为。附加(关联对象);
}
}
附加时受保护的覆盖无效()
{
foreach(BehaviorCollection中的var行为)
{
behavior.Detach();
}
}
}
下面是幻灯片CompositeBehavior:CompositeBehavior(为了简单起见,只显示一个依赖项)

公共密封类SliderCompositeBhavior:CompositeBhavior
{
私有滑块主机=>AssociatedObject;
公共静态只读DependencyProperty SourceValueProperty=
从属属性。寄存器(
名称(源值),
类型(双),
类型(滑块组件行为),
新框架属性元数据(
0d,
默认情况下,FrameworkPropertyMetadataOptions.BindsTwoWay,
来源价值(已更改);
//装订好了吗
公共双源值
{
获取{return(double)Host.GetValue(SourceValueProperty);}
set{Host.SetValue(SourceValueProperty,value);}
}
//用于包含行为的附加属性。
公共静态void SetSourceValue(滑块主机,双值)
{
SetValue(SourceValueProperty,value);
}
公共静态双GetSourceValue(Slider主机)
{
return(double)host.GetValue(SourceValueProperty);
}
资源值上的私有静态无效已更改(DependencyObject dpo、DependencyPropertyChangedEventArgs args)
{
var soruce=(SliderCompositeBehavior)dpo;
soruce.Host.Value=(双精度)args.NewValue;
}
}
现在我看到了两个问题

  • 包含行为的内部依赖项属性定义根本不起作用

  • 过度绑定依赖项属性的元数据不适用于包含属性

内部
DragCompletedCommandBehavior:Behavior
我有

public sealed class DragCompletedCommandBehavior : Behavior<Slider>
{
    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register(
            nameof(Command),
            typeof(ICommand),
            typeof(DragCompletedCommandBehavior));
}
公共密封类DragCompletedCommand行为:行为
{
公共ICommand命令
{
获取{return(ICommand)GetValue(CommandProperty);}
set{SetValue(CommandProperty,value);}
}
公共静态只读DependencyProperty CommandProperty=
从属属性。寄存器(
姓名(指挥部),
类型(ICommand),
类型(DragCompletedCommandBehavior));
}
我在输出时得到这个错误。(这不会引发异常。它在程序启动后隐藏在输出显示的某个位置。)

System.Windows.Data错误:2:找不到目标元素的治理FrameworkElement或FrameworkContentElement。BindingExpression:Path=SeekTo;DataItem=null;目标元素是“DragCompletedCommandBehavior”(HashCode=52056421);目标属性为“Command”(类型为“ICommand”)

在另一个行为中,我有这个

public sealed class LockOnDragBehavior : Behavior<Slider>
{
    static LockOnDragBehavior()
    {
        SliderCompositeBehavior.SourceValueProperty.OverrideMetadata(
            typeof(LockOnDragBehavior),
            new FrameworkPropertyMetadata(
                0d,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnSourceValueChanged));
    }

    private static void OnSourceValueChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args)
    {
        // do something
    }
}
公共密封类LockOnDragBehavior:行为
{
静态锁定行为()
{
SliderCompositeBhavior.SourceValueProperty.OverrideMetadata(
类型(LockOnDragBehavior),
新框架属性元数据(
0d,
默认情况下,FrameworkPropertyMetadataOptions.BindsTwoWay,
来源价值(已更改);
}
资源值上的私有静态无效已更改(DependencyObject dpo、DependencyPropertyChangedEventArgs args)
{
//做点什么
}
}
但是
OnSourceValueChanged
从不触发。这个
public sealed class DragCompletedCommandBehavior : Behavior<Slider>
{
    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register(
            nameof(Command),
            typeof(ICommand),
            typeof(DragCompletedCommandBehavior));
}
public sealed class LockOnDragBehavior : Behavior<Slider>
{
    static LockOnDragBehavior()
    {
        SliderCompositeBehavior.SourceValueProperty.OverrideMetadata(
            typeof(LockOnDragBehavior),
            new FrameworkPropertyMetadata(
                0d,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnSourceValueChanged));
    }

    private static void OnSourceValueChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args)
    {
        // do something
    }
}
[ContentProperty(nameof(BehaviorCollection))]
public abstract class CompositeBehavior<T> : Behavior<T>
    where T : DependencyObject
{
    #region Behavior Collection

    public static readonly DependencyProperty BehaviorCollectionProperty =
        DependencyProperty.Register(
            $"{nameof(CompositeBehavior<T>)}<{typeof(T).Name}>",
            typeof(BehaviorCollection),
            typeof(CompositeBehavior<T>),
            new FrameworkPropertyMetadata(
                null,
                FrameworkPropertyMetadataOptions.NotDataBindable));

    public BehaviorCollection BehaviorCollection
    {
        get
        {
            var collection = GetValue(BehaviorCollectionProperty) as BehaviorCollection;

            if (collection == null)
            {
                var constructor = typeof(BehaviorCollection)
                    .GetConstructor(
                        BindingFlags.NonPublic | BindingFlags.Instance,
                        null, Type.EmptyTypes, null);

                collection = (BehaviorCollection) constructor.Invoke(null);
                collection.Changed += OnCollectionChanged;
                SetValue(BehaviorCollectionProperty, collection);
            }

            return collection;
        }
    }

    private void OnCollectionChanged(object sender, EventArgs eventArgs)
    {
        var hashset = new HashSet<Type>();
        foreach (var behavior in BehaviorCollection)
        {
            if (behavior is Behavior<T> == false)
            {
                throw new InvalidOperationException($"{behavior.GetType()} does not inherit from {typeof(Behavior<T>)}.");
            }
            if (hashset.Add(behavior.GetType()) == false)
            {
                throw new InvalidOperationException($"{behavior.GetType()} is set more than once.");
            }
        }
    }

    #endregion

    protected sealed override void OnAttached()
    {
        OnSelfAttached();
        foreach (var behavior in BehaviorCollection)
        {
            behavior.Attach(AssociatedObject);
        }
    }

    protected sealed override void OnDetaching()
    {
        OnSelfDetaching();
        foreach (var behavior in BehaviorCollection)
        {
            behavior.Detach();
        }
    }

    protected virtual void OnSelfAttached()
    {
    }

    protected virtual void OnSelfDetaching()
    {
    }
}