如何从Style设置交互行为

问题描述 投票:0回答:3

我在 XAML 中多次重复我的代码

重复代码=

                    <TextBox Margin="5" MinWidth="50">
                        <i:Interaction.Behaviors>
                            <behaviors:TextBoxMaxValueBehavior MaxValue="4"/>
                            <behaviors:TextBoxNoLettersBehavior/>
                            <behaviors:SelectAllTextOnFocusBehavior/>
                        </i:Interaction.Behaviors>
                    </TextBox>

模板代码 =

        <Style TargetType="TextBox">
            <Setter Property="i:Interaction.Behaviors">
                <Setter.Value>
                    <i:BehaviorCollection>
                        <behaviors:SelectAllTextOnFocusBehavior/>
                    </i:BehaviorCollection>
                </Setter.Value>
            </Setter>
        </Style>

错误 = 'BehaviorCollection 不能用作对象元素,因为它不是公共的,或者没有定义公共无参数构造函数或类型转换器。

无效类型:预期类型是“DependencyProperty”,实际类型是“Behavior Collection”。

我的问题在我正在使用的模板代码中......我认为这可能会更容易。

感谢您的宝贵时间!

c# .net wpf xaml
3个回答
2
投票

我创建了一个辅助实用程序来允许将行为类包含在样式定义中。

public class BehaviorForStyle<TTarget, TBehavior> : Behavior<TTarget>
    where TTarget : DependencyObject
    where TBehavior : BehaviorForStyle<TTarget, TBehavior>, new()
{
    public static readonly DependencyProperty IsEnabledForStyleProperty =
        DependencyProperty.RegisterAttached("IsEnabledForStyle",
            typeof(bool),
            typeof(BehaviorForStyle<TTarget, TBehavior>),
            new FrameworkPropertyMetadata(false, OnIsEnabledForStyleChanged));

    public bool IsEnabledForStyle
    {
        get => (bool)GetValue(IsEnabledForStyleProperty);
        set => SetValue(IsEnabledForStyleProperty, value);
    }

    private static void OnIsEnabledForStyleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        if (args.NewValue is bool newValue)
        {
            var behaviors = Interaction.GetBehaviors(sender);
            var existingBehavior = behaviors.FirstOrDefault(b => b.GetType() == typeof(TBehavior)) as TBehavior;

            if (!newValue && existingBehavior != null)
            {
                behaviors.Remove(existingBehavior);
            }
            else if (newValue && existingBehavior == null)
            {
                behaviors.Add(new TBehavior());
            }
        }
    }
}

现在行为类应该从

BehaviorForStyle<>
下降,而不仅仅是
Behavior<>

例如

public class BlockWindowAltF4CloseBehavior : BehaviorForStyle<Window, BlockWindowAltF4CloseBehavior>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.KeyDown += OnKeyDown;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.KeyDown -= OnKeyDown;
        base.OnDetaching();
    }

    private static void OnKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.System && e.SystemKey == Key.F4)
        {
            e.Handled = true;
        }
    }
}

以及风格的用法

<Style TargetType="Window">
    <Setter Property="help:BlockWindowAltF4CloseBehavior.IsEnabledForStyle" Value="True" />
    ...
</style>

2
投票

一个简单的可重复使用的解决方案是创建一个自定义附加行为,该行为收集交互行为以将它们应用到附加对象上:

使用示例

<Style TargetType="TextBox">
  <Setter Property="InteractionBehaviorCollector.InteractionBehaviors">
    <Setter.Value>
      <InteractionBehaviorCollection>
        <TextBoxMaxValueBehavior MaxValue="4"/>
        <TextBoxNoLettersBehavior/>
        <SelectAllTextOnFocusBehavior/>
      </InteractionBehaviorCollection>
    </Setter.Value>
  </Setter>
</Style>

InteractionBehaviorCollection.cs
创建可在 XAML 中使用的集合:

public class InteractionBehaviorCollection : List<Behavior>
{
  public InteractionBehaviorCollection()
  {
  }

  public InteractionBehaviorCollection(IEnumerable<Behavior> collection) : base(collection)
  {
  }

  public InteractionBehaviorCollection(int capacity) : base(capacity)
  {
  }
}

InteractionBehaviorCollector.cs
创建收集并应用交互行为的附加行为:

public class InteractionBehaviorCollector : DependencyObject
{
  public static InteractionBehaviorCollection GetInteractionBehaviors(DependencyObject attachingElement) 
    => (InteractionBehaviorCollection)attachingElement.GetValue(InteractionBehaviorsProperty);

  public static void SetInteractionBehaviors(DependencyObject attachingElement, InteractionBehaviorCollection value) 
    => attachingElement.SetValue(InteractionBehaviorsProperty, value);

  public static readonly DependencyProperty InteractionBehaviorsProperty = DependencyProperty.RegisterAttached(
    "InteractionBehaviors",
    typeof(InteractionBehaviorCollection),
    typeof(InteractionBehaviorCollector),
    new PropertyMetadata(default(InteractionBehaviorCollection), OnInteractionBehaviorsChanged));

  private static void OnInteractionBehaviorsChanged(DependencyObject attachingElement, DependencyPropertyChangedEventArgs e)
  {    
    if (e.OldValue is InteractionBehaviorCollection oldBehaviors)
    {
      BehaviorCollection interactionBehaviors = Interaction.GetBehaviors(attachingElement);
      foreach (Behavior behavior in oldBehaviors)
      {
        _ = interactionBehaviors.Remove(behavior);
      }
    }

    if (e.NewValue is InteractionBehaviorCollection newBehaviors)
    {
      BehaviorCollection interactionBehaviors = Interaction.GetBehaviors(attachingElement);      
      foreach (Behavior behavior in newBehaviors)
      {
        interactionBehaviors.Add(behavior);
      }
    }
  }
}

1
投票

定义行为的附加属性 首先,您需要在单独的类中定义附加属性来管理行为。这是 C# 中的示例:

using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Controls;

namespace YourNamespace
{
    public static class TextBoxBehaviors
    {
        public static readonly DependencyProperty UseBehaviorsProperty =
            DependencyProperty.RegisterAttached(
                "UseBehaviors",
                typeof(bool),
                typeof(TextBoxBehaviors),
                new PropertyMetadata(false, OnUseBehaviorsChanged));

        public static bool GetUseBehaviors(DependencyObject obj)
        {
            return (bool)obj.GetValue(UseBehaviorsProperty);
        }

        public static void SetUseBehaviors(DependencyObject obj, bool value)
        {
            obj.SetValue(UseBehaviorsProperty, value);
        }

        private static void OnUseBehaviorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TextBox textBox)
            {
                var behaviors = Interaction.GetBehaviors(textBox);

                if ((bool)e.NewValue)
                {
                    // Add your behaviors here
                    behaviors.Add(new TextBoxMaxValueBehavior { MaxValue = 4 });
                    behaviors.Add(new TextBoxNoLettersBehavior());
                    behaviors.Add(new SelectAllTextOnFocusBehavior());
                }
                else
                {
                    behaviors.Clear();
                }
            }
        }
    }
}

在 XAML 中使用附加属性 现在,您可以使用 XAML 中的附加属性将行为应用到任何 TextBox:

<Window x:Class="YourNamespace.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:behaviors="clr-namespace:YourNamespace"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <TextBox Margin="5" MinWidth="50" behaviors:TextBoxBehaviors.UseBehaviors="True"/>
    <TextBox Margin="5" MinWidth="50" behaviors:TextBoxBehaviors.UseBehaviors="True"/>
    <!-- Add more TextBox elements as needed -->
</Grid>
© www.soinside.com 2019 - 2024. All rights reserved.