微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何编写可以承载可变数量的子属性/元素/xaml 标签的行为

如何解决如何编写可以承载可变数量的子属性/元素/xaml 标签的行为

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

为此,该行为有一个 List<> Dependency 属性来接收内容

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);
}

并且内容是作为派生自 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),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>

现在是有效的:

  • behav:StatefulFocusManagerBehaviorFocusTarget 属性绑定按预期工作
  • behav:FocusTarget 实例的属性 StateName 已按预期设置
  • behav:FocusTarget 实例的 Target 属性始终设置为 null

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

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

<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>());
   }
}

然后,不是从 FrameworkElement 中的 FocusTarget 继承,而是从 Freezable 派生。

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

   // ...your other code.
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。