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