我在 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”。
我的问题在我正在使用的模板代码中......我认为这可能会更容易。
感谢您的宝贵时间!
我创建了一个辅助实用程序来允许将行为类包含在样式定义中。
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>
一个简单的可重复使用的解决方案是创建一个自定义附加行为,该行为收集交互行为以将它们应用到附加对象上:
<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);
}
}
}
}
定义行为的附加属性 首先,您需要在单独的类中定义附加属性来管理行为。这是 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>