我已经装箱的按钮混合行为。 我怎么可以设置所有我的应用程序的按钮。
<Button ...>
<i:Interaction.Behaviors>
<local:MyBehavior />
</i:Interaction.Behaviors>
</Button>
然而,当我尝试:
<Style>
<Setter Property="i:Interaction.Behaviors">
<Setter.Value>
<local:MyBehavior />
</Setter.Value>
</Setter>
</Style>
我得到的错误
属性“行为”不具有可访问的制定者。
我有同样的问题,我已经想出了一个解决方案。 我发现这个问题后,我解决了它,我看到我的解决方案蕴藏着很多共同的马克。 然而,这种方法有点不同。
主要的问题是,行为和触发器与相关联的特定对象,所以你不能使用多个不同的关联对象行为的同一个实例。 当你定义自己的行为内嵌XAML强制执行此一比一的关系。 但是,当您尝试设置在样式行为,样式可以重新使用它适用于所有对象,这将扔在基本行为的类例外。 事实上,作者去相当大的努力,以阻止我们甚至试图做到这一点,知道这是行不通的。
第一个问题是,我们甚至不能建立一个行为,二传值,因为构造函数是内部。 所以,我们需要自己的行为,并触发集合类。
接下来的问题是,行为和触发附加属性没有制定者,所以他们只能被添加到在线XAML。 这个问题我们与操纵的主要行为和触发器属性自己的附加属性解决。
第三个问题是,我们的行为集合是只针对单一型靶好。 这是我们解决了利用很少使用XAML的功能x:Shared="False"
,其创建的每个被引用的时间资源的新副本。
最后一个问题是,行为和触发器不像其他的风格制定者; 我们不希望以取代旧的行为与新的行为,因为他们可以做的疯狂不同的事情。 因此,如果我们承认,一旦你添加一个行为,你不能把它拿走(这就是行为目前的工作方式),我们可以得出结论,行为和触发器应该是添加剂,这可以通过我们的附加属性进行处理。
下面是使用这种方法的例子:
<Grid>
<Grid.Resources>
<sys:String x:Key="stringResource1">stringResource1</sys:String>
<local:Triggers x:Key="debugTriggers" x:Shared="False">
<i:EventTrigger EventName="MouseLeftButtonDown">
<local:DebugAction Message="DataContext: {0}" MessageParameter="{Binding}"/>
<local:DebugAction Message="ElementName: {0}" MessageParameter="{Binding Text, ElementName=textBlock2}"/>
<local:DebugAction Message="Mentor: {0}" MessageParameter="{Binding Text, RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}}"/>
</i:EventTrigger>
</local:Triggers>
<Style x:Key="debugBehavior" TargetType="FrameworkElement">
<Setter Property="local:SupplementaryInteraction.Triggers" Value="{StaticResource debugTriggers}"/>
</Style>
</Grid.Resources>
<StackPanel DataContext="{StaticResource stringResource1}">
<TextBlock Name="textBlock1" Text="textBlock1" Style="{StaticResource debugBehavior}"/>
<TextBlock Name="textBlock2" Text="textBlock2" Style="{StaticResource debugBehavior}"/>
<TextBlock Name="textBlock3" Text="textBlock3" Style="{StaticResource debugBehavior}"/>
</StackPanel>
</Grid>
本例使用触发器,但行为的工作方式相同。 在这个例子中,我们展示:
- 风格可以适用于多个文本块
- 几种类型的数据的正确绑定的所有工作
- 在输出窗口中生成的文本调试动作
下面是一个例子行为,我们DebugAction
。 更正确的是一个动作,而是通过语言的滥用,我们称之为行为,触发器和行为“行为”。
public class DebugAction : TriggerAction<DependencyObject>
{
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(DebugAction), new UIPropertyMetadata(""));
public object MessageParameter
{
get { return (object)GetValue(MessageParameterProperty); }
set { SetValue(MessageParameterProperty, value); }
}
public static readonly DependencyProperty MessageParameterProperty =
DependencyProperty.Register("MessageParameter", typeof(object), typeof(DebugAction), new UIPropertyMetadata(null));
protected override void Invoke(object parameter)
{
Debug.WriteLine(Message, MessageParameter, AssociatedObject, parameter);
}
}
最后,我们的收藏和附加属性,使这一切工作。 通过与类比Interaction.Behaviors
,你的目标的属性被称为SupplementaryInteraction.Behaviors
因为通过设置该属性,将行为添加到Interaction.Behaviors
,同样的触发器。
public class Behaviors : List<Behavior>
{
}
public class Triggers : List<TriggerBase>
{
}
public static class SupplementaryInteraction
{
public static Behaviors GetBehaviors(DependencyObject obj)
{
return (Behaviors)obj.GetValue(BehaviorsProperty);
}
public static void SetBehaviors(DependencyObject obj, Behaviors value)
{
obj.SetValue(BehaviorsProperty, value);
}
public static readonly DependencyProperty BehaviorsProperty =
DependencyProperty.RegisterAttached("Behaviors", typeof(Behaviors), typeof(SupplementaryInteraction), new UIPropertyMetadata(null, OnPropertyBehaviorsChanged));
private static void OnPropertyBehaviorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behaviors = Interaction.GetBehaviors(d);
foreach (var behavior in e.NewValue as Behaviors) behaviors.Add(behavior);
}
public static Triggers GetTriggers(DependencyObject obj)
{
return (Triggers)obj.GetValue(TriggersProperty);
}
public static void SetTriggers(DependencyObject obj, Triggers value)
{
obj.SetValue(TriggersProperty, value);
}
public static readonly DependencyProperty TriggersProperty =
DependencyProperty.RegisterAttached("Triggers", typeof(Triggers), typeof(SupplementaryInteraction), new UIPropertyMetadata(null, OnPropertyTriggersChanged));
private static void OnPropertyTriggersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var triggers = Interaction.GetTriggers(d);
foreach (var trigger in e.NewValue as Triggers) triggers.Add(trigger);
}
}
有你有它,全功能的行为,并触发应用通过样式。
总结答案,这篇大文章的风格混合行为 ,我来到这个普通的短,方便易的解决方案:
我做了泛型类,这可以通过任何行为被继承。
public class AttachableForStyleBehavior<TComponent, TBehavior> : Behavior<TComponent>
where TComponent : System.Windows.DependencyObject
where TBehavior : AttachableForStyleBehavior<TComponent, TBehavior> , new ()
{
public static DependencyProperty IsEnabledForStyleProperty =
DependencyProperty.RegisterAttached("IsEnabledForStyle", typeof(bool),
typeof(AttachableForStyleBehavior<TComponent, TBehavior>), new FrameworkPropertyMetadata(false, OnIsEnabledForStyleChanged));
public bool IsEnabledForStyle
{
get { return (bool)GetValue(IsEnabledForStyleProperty); }
set { SetValue(IsEnabledForStyleProperty, value); }
}
private static void OnIsEnabledForStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement uie = d as UIElement;
if (uie != null)
{
var behColl = Interaction.GetBehaviors(uie);
var existingBehavior = behColl.FirstOrDefault(b => b.GetType() ==
typeof(TBehavior)) as TBehavior;
if ((bool)e.NewValue == false && existingBehavior != null)
{
behColl.Remove(existingBehavior);
}
else if ((bool)e.NewValue == true && existingBehavior == null)
{
behColl.Add(new TBehavior());
}
}
}
}
所以,你可以简单地用许多这样的组件的重用:
public class ComboBoxBehaviour : AttachableForStyleBehavior<ComboBox, ComboBoxBehaviour>
{ ... }
而在XAML足够声明:
<Style TargetType="ComboBox">
<Setter Property="behaviours:ComboBoxBehaviour.IsEnabledForStyle" Value="True"/>
所以basicly的AttachableForStyleBehavior类所做的事情XAML,登记行为的实例在风格上每个组件。 有关详细信息,请参阅链接。
1.创建附加属性
public static class DataGridCellAttachedProperties
{
//Register new attached property
public static readonly DependencyProperty IsSingleClickEditModeProperty =
DependencyProperty.RegisterAttached("IsSingleClickEditMode", typeof(bool), typeof(DataGridCellAttachedProperties), new UIPropertyMetadata(false, OnPropertyIsSingleClickEditModeChanged));
private static void OnPropertyIsSingleClickEditModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var dataGridCell = d as DataGridCell;
if (dataGridCell == null)
return;
var isSingleEditMode = GetIsSingleClickEditMode(d);
var behaviors = Interaction.GetBehaviors(d);
var singleClickEditBehavior = behaviors.SingleOrDefault(x => x is SingleClickEditDataGridCellBehavior);
if (singleClickEditBehavior != null && !isSingleEditMode)
behaviors.Remove(singleClickEditBehavior);
else if (singleClickEditBehavior == null && isSingleEditMode)
{
singleClickEditBehavior = new SingleClickEditDataGridCellBehavior();
behaviors.Add(singleClickEditBehavior);
}
}
public static bool GetIsSingleClickEditMode(DependencyObject obj)
{
return (bool) obj.GetValue(IsSingleClickEditModeProperty);
}
public static void SetIsSingleClickEditMode(DependencyObject obj, bool value)
{
obj.SetValue(IsSingleClickEditModeProperty, value);
}
}
2.创建一个行为
public class SingleClickEditDataGridCellBehavior:Behavior<DataGridCell>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseLeftButtonDown += DataGridCellPreviewMouseLeftButtonDown;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.PreviewMouseLeftButtonDown += DataGridCellPreviewMouseLeftButtonDown;
}
void DataGridCellPreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
{
if (!cell.IsFocused)
{
cell.Focus();
}
DataGrid dataGrid = LogicalTreeWalker.FindParentOfType<DataGrid>(cell); //FindVisualParent<DataGrid>(cell);
if (dataGrid != null)
{
if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
{
if (!cell.IsSelected)
cell.IsSelected = true;
}
else
{
DataGridRow row = LogicalTreeWalker.FindParentOfType<DataGridRow>(cell); //FindVisualParent<DataGridRow>(cell);
if (row != null && !row.IsSelected)
{
row.IsSelected = true;
}
}
}
}
}
}
3.创建一个样式,并设置附加属性
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Behaviors:DataGridCellAttachedProperties.IsSingleClickEditMode" Value="True"/>
</Style>
我还有一个想法,以避免附加属性的每一个行为的产生:
行为创造者界面:
public interface IBehaviorCreator { Behavior Create(); }
小帮手集合:
public class BehaviorCreatorCollection : Collection<IBehaviorCreator> { }
辅助类附加行为:
public static class BehaviorInStyleAttacher { #region Attached Properties public static readonly DependencyProperty BehaviorsProperty = DependencyProperty.RegisterAttached( "Behaviors", typeof(BehaviorCreatorCollection), typeof(BehaviorInStyleAttacher), new UIPropertyMetadata(null, OnBehaviorsChanged)); #endregion #region Getter and Setter of Attached Properties public static BehaviorCreatorCollection GetBehaviors(TreeView treeView) { return (BehaviorCreatorCollection)treeView.GetValue(BehaviorsProperty); } public static void SetBehaviors( TreeView treeView, BehaviorCreatorCollection value) { treeView.SetValue(BehaviorsProperty, value); } #endregion #region on property changed methods private static void OnBehaviorsChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) { if (e.NewValue is BehaviorCreatorCollection == false) return; BehaviorCreatorCollection newBehaviorCollection = e.NewValue as BehaviorCreatorCollection; BehaviorCollection behaviorCollection = Interaction.GetBehaviors(depObj); behaviorCollection.Clear(); foreach (IBehaviorCreator behavior in newBehaviorCollection) { behaviorCollection.Add(behavior.Create()); } } #endregion }
现在你的行为,它实现IBehaviorCreator:
public class SingleClickEditDataGridCellBehavior:Behavior<DataGridCell>, IBehaviorCreator { //some code ... public Behavior Create() { // here of course you can also set properties if required return new SingleClickEditDataGridCellBehavior(); } }
而现在在XAML中使用它:
<Style TargetType="{x:Type DataGridCell}"> <Setter Property="helper:BehaviorInStyleAttacher.Behaviors" > <Setter.Value> <helper:BehaviorCreatorCollection> <behaviors:SingleClickEditDataGridCellBehavior/> </helper:BehaviorCreatorCollection> </Setter.Value> </Setter> </Style>
我无法找到原来的文章,但我能够重新创建的效果。
#region Attached Properties Boilerplate
public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached("IsActive", typeof(bool), typeof(ScrollIntoViewBehavior), new PropertyMetadata(false, OnIsActiveChanged));
public static bool GetIsActive(FrameworkElement control)
{
return (bool)control.GetValue(IsActiveProperty);
}
public static void SetIsActive(
FrameworkElement control, bool value)
{
control.SetValue(IsActiveProperty, value);
}
private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behaviors = Interaction.GetBehaviors(d);
var newValue = (bool)e.NewValue;
if (newValue)
{
//add the behavior if we don't already have one
if (!behaviors.OfType<ScrollIntoViewBehavior>().Any())
{
behaviors.Add(new ScrollIntoViewBehavior());
}
}
else
{
//remove any instance of the behavior. (There should only be one, but just in case.)
foreach (var item in behaviors.ToArray())
{
if (item is ScrollIntoViewBehavior)
behaviors.Remove(item);
}
}
}
#endregion
<Style TargetType="Button">
<Setter Property="Blah:ScrollIntoViewBehavior.IsActive" Value="True" />
</Style>
声明个体行为/触发的资源:
<Window.Resources>
<i:EventTrigger x:Key="ET1" EventName="Click">
<ei:ChangePropertyAction PropertyName="Background">
<ei:ChangePropertyAction.Value>
<SolidColorBrush Color="#FFDAD32D"/>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
</Window.Resources>
将其插入集合中:
<Button x:Name="Btn1" Content="Button">
<i:Interaction.Triggers>
<StaticResourceExtension ResourceKey="ET1"/>
</i:Interaction.Triggers>
</Button>
行为的代码需要一个视觉,所以我们只能在视觉添加。 所以我能看到的唯一选择是添加到控件模板内的元素之一,以获得行为添加到样式上的具体控制的所有实例的影响。
文章介绍附加行为WPF中只使用风格实现了一个附加的行为,也可以与或有帮助。
在“简介附加行为”一文的技术避免了交互标签干脆,使用上的样式。 我不知道这是否只是因为它是一个比较过时的技术,或者,如果仍然赋予了一些好处,其中一个应该更喜欢它在某些情况下。
我喜欢在这个线程的答案被罗马Dvoskin和乔纳森·艾伦所示的方法。 当我第一次学习这种技术虽然,我受益匪浅这个博客帖子 ,提供有关的技术更多的解释。 而看到的来龙去脉, 这里是整个源代码的类,在他的博客关于作者会谈。