如何编写可以承载可变数量 child properties/elements/xaml-tags 的行为

How to write a behavior that can host a variable number of child properties/elements/xaml-tags

我创建了一个 Interaction.Behavior 行为,需要接收可变数量的输入。

为此,该行为有一个 List<> 依赖关系 属性 来接收内容:

private static readonly DependencyPropertyKey FocusTargetsPropertyKey = DependencyProperty.RegisterReadOnly("Targets", typeof(List<FocusTarget>), typeof(StatefulFocusManagerBehavior), new PropertyMetadata(new List<FocusTarget>()));

public static readonly DependencyProperty FocusTargetsProperty = FocusTargetsPropertyKey.DependencyProperty;

public List<FocusTarget> Targets
{
    get => (List<FocusTarget>)this.GetValue(FocusTargetsProperty);
    set => this.SetValue(FocusTargetsProperty, value);
}

并且内容实现为 class FocusTarget 派生自 FrameworkElement:

public class FocusTarget : FrameworkElement
{
    
    #region DepProp: FocusTarget

    public static readonly DependencyProperty FocusTargetProperty = DependencyProperty.Register("Target", typeof(FrameworkElement), typeof(FocusTarget), new PropertyMetadata(null));

    public FrameworkElement Target
    {
        get => (FrameworkElement)this.GetValue(FocusTargetProperty);
        set => this.SetValue(FocusTargetProperty, value);
    }

    #endregion

    #region DepProp: StateName

    public static readonly DependencyProperty StateNameProperty = DependencyProperty.Register("StateName", typeof(string), typeof(FocusTarget), new PropertyMetadata(null));

    public string StateName
    {
        get => (string)this.GetValue(StateNameProperty);
        set => this.SetValue(StateNameProperty, value);
    }

    #endregion
}

行为声明如下:

<b:Interaction.Behaviors>
    <behav:StatefulFocusManagerBehavior FocusTarget="{Binding ElementName=txtResponse}">
        <behav:StatefulFocusManagerBehavior.Targets>
            <behav:FocusTarget Target="{Binding ElementName=txtResponse}"  StateName="Text"  />
            <behav:FocusTarget Target="{Binding ElementName=QnAToggle}"    StateName="Toggle"/>
        </behav:StatefulFocusManagerBehavior.Targets>
    </behav:StatefulFocusManagerBehavior>
</b:Interaction.Behaviors>

现在有一个有效的方法:

我确实怀疑这可能是 DataContext 问题,但无法验证也无法消除它,让我对可能的问题和解决方案感到困惑。

我尝试设置 DataContext,但此绑定不起作用,并给我 null:

<behav:FocusTarget Target="{Binding ElementName=txtResponse}"   
                   StateName="Text"
                   DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}"  />

继承数据上下文和访问行为集合中的元素不会那样工作,因为集合不在可视化树中,也不是启用绑定的 FrameworkElementFreezable

FocusTargetsProperty 更改为 FreezableCollection<FocusTarget> 而不是 List<FocusTarget>。此外,确保在构造函数中分配集合的新实例。

public class StatefulFocusManagerBehavior : Behavior<FrameworkElement>
{
   private static readonly DependencyPropertyKey FocusTargetsPropertyKey = DependencyProperty.RegisterReadOnly("Targets", typeof(FreezableCollection<FocusTarget>), typeof(StatefulFocusManagerBehavior), new PropertyMetadata(null));

   public static readonly DependencyProperty FocusTargetsProperty = FocusTargetsPropertyKey.DependencyProperty;

   public FreezableCollection<FocusTarget> Targets
   {
      get => (FreezableCollection<FocusTarget>)this.GetValue(FocusTargetsProperty);
      set => this.SetValue(FocusTargetsProperty, value);
   }

   public StatefulFocusManagerBehavior()
   {
      SetValue(FocusTargetsPropertyKey, new FreezableCollection<FocusTarget>());
   }
}

然后,不是从 FocusTarget 中的 FrameworkElement 继承,而是从 Freezable.

派生
public class FocusTarget : Freezable
{
   protected override Freezable CreateInstanceCore()
   {
      return new FocusTarget();
   }

   // ...your other code.
}