我試圖使任意簡單行爲組成的複合行爲。我發現行爲非常靈活的製作自定義控件的方式。依賴屬性不起作用(使複合行爲)
目前我有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:Interaction.Behaviors>
<sb:FreeSlideBehavior/>
</i:Interaction.Behaviors>
這裏是CompositeBehavior<T> : Behavior<T>
:
[ContentProperty(nameof(BehaviorCollection))]
public abstract class CompositeBehavior<T> : Behavior<T>
where T : DependencyObject
{
public static readonly DependencyProperty BehaviorCollectionProperty =
DependencyProperty.Register(
$"{nameof(CompositeBehavior<T>)}<{typeof(T).Name}>",
typeof(ObservableCollection<Behavior<T>>),
typeof(CompositeBehavior<T>),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.NotDataBindable));
public ObservableCollection<Behavior<T>> BehaviorCollection
{
get
{
var collection = GetValue(BehaviorCollectionProperty) as ObservableCollection<Behavior<T>>;
if (collection == null)
{
collection = new ObservableCollection<Behavior<T>>();
collection.CollectionChanged += OnCollectionChanged;
SetValue(BehaviorCollectionProperty, collection);
}
return collection;
}
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
// some code to throw exception when same behavior is set more than once.
}
protected override void OnAttached()
{
foreach (var behavior in BehaviorCollection)
{
behavior.Attach(AssociatedObject);
}
}
protected override void OnDetaching()
{
foreach (var behavior in BehaviorCollection)
{
behavior.Detach();
}
}
}
這裏是(被示出爲簡單起見,僅一個從屬關係)的SliderCompositeBehavior : CompositeBehavior<Slider>
public sealed class SliderCompositeBehavior : CompositeBehavior<Slider>
{
private Slider Host => AssociatedObject;
public static readonly DependencyProperty SourceValueProperty =
DependencyProperty.Register(
nameof(SourceValue),
typeof(double),
typeof(SliderCompositeBehavior),
new FrameworkPropertyMetadata(
0d,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnSourceValueChanged));
// does the binding
public double SourceValue
{
get { return (double)Host.GetValue(SourceValueProperty); }
set { Host.SetValue(SourceValueProperty, value); }
}
// attached property for containing behaviors.
public static void SetSourceValue(Slider host, double value)
{
host.SetValue(SourceValueProperty, value);
}
public static double GetSourceValue(Slider host)
{
return (double)host.GetValue(SourceValueProperty);
}
private static void OnSourceValueChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args)
{
var soruce = (SliderCompositeBehavior)dpo;
soruce.Host.Value = (double)args.NewValue;
}
}
現在有兩個問題,我可以看到。
包含行爲的依賴屬性定義完全不起作用。
重寫依賴項屬性的元數據不適用於包含屬性。
裏面DragCompletedCommandBehavior : Behavior<Slider>
我
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));
}
我得到的輸出此錯誤。 (這並不拋出異常。它在輸出顯示的某處隱藏程序啓動後。)
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=SeekTo; DataItem=null; target element is 'DragCompletedCommandBehavior' (HashCode=52056421); target property is 'Command' (type '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
}
}
但是OnSourceValueChanged
絕不會發生火災。但SliderCompositeBehavior
內部的主要OnSourceValueChanged
仍在觸發。但新的元數據只是無所事事。
我該如何解決這些問題?我不明白爲什麼包含行爲中的依賴屬性不起作用。有人可以解釋爲什麼嗎?非常感謝。
是的。但正如我所說,如果直接添加它們,這些行爲可能會相互衝突。我能夠做你的話。但是每一種行爲都會變得更大。因爲我必須爲每個行爲寫同樣的東西。例如共享的「Thumb」屬性。或者我用來同步這些行爲的一些其他屬性。 –
這裏學習速度慢..現在得到了。 – WPFUser
@WPFUser修好了;) –