私は任意の単純な動作で構成される複合的な動作をしようとしています。私は、ビヘイビアがカスタムコントロールを作成する非常に柔軟な方法を見つけました。依存関係のプロパティが機能しない(複合的な動作をする)
現在、私は5つの動作をスライダーに実装しています。彼らは互いに衝突する可能性があります。
これらの動作は、1つのコントロール用に設計されています。私はそれらのそれぞれが互いに矛盾することなく独立して働くように設計することができました(私はこれを実行し、うまくいきましたが、ちょうど醜いのですべてを取り除いた)。
ポイント、私はすべての動作のために同じコードを書き直したくありません。
私は1つのコントロールに対して複合的な動作をさせようとしています。この振る舞いには、すべての包含動作で共有されるいくつかの添付プロパティがあります。そのためにこれらの行動は互いに衝突しない。また、多くのコードの冗長性がなくなりました。今や行動を含むことがずっと簡単になります。
ここでは、より良いアイデアを得るための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;
}
}
は、今私が見ることができる2つの問題がある(唯一の依存関係が簡略化のために示されている)です。
振る舞いを含む内部の依存性プロパティ定義はまったく機能しません。
依存プロパティのオーバーライドメタデータは、プロパティを含むためには機能しません。
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
は発生しません。メインOnSourceValueChanged
SliderCompositeBehavior
の内部がまだ発火します。新しいメタデータは何もしません。
これらの問題を解決するにはどうすればよいですか?なぜ私は挙動を含む内部の依存関係のプロパティが機能しないのか分かりません。何らかの理由で説明できますか?どうもありがとうございます。
はい。私が言ったように、これらの振る舞いは、私がそれらを直接追加すると、互いに衝突する可能性があります。私はあなたの言うことをすることができました。すべての行動はもっと大きくなります。なぜなら、私はそれぞれの行動に対して同じことを書く必要があるからです。たとえば、共有される 'Thumb'プロパティです。またはこれらの動作を同期させるために使用するその他のプロパティ –
ここではスロー学習者がいます。 – WPFUser
@WPFUserが修正されました;) –