在 BasedOn / inherited Style 中更改触发顺序
Change Trigger order in BasedOn / inherited Style
我有一个基地 Style
- DataGridRowSelectionStyle
。在某些 DataGrids
上,我需要扩展此 Style
以添加 background
.
DataGridRowSelectionStyle
<Style TargetType="DataGridRow" x:Key="DataGridRowSelectionStyle">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsMouseOver}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsSelected}"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
行样式
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowSelectionStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.OK}">
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Green}"/>
</DataTrigger>
<DataTrigger Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.NG}">
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Red}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
因为Trigger
顺序,两个碱基Triggers
被覆盖,IsMouseOver
或IsSelected
不再触发
解决方案 1:扩展 RowStyle
。非常糟糕的解决方案,因为我不再需要我的基地 Style
..
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowSelectionStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.OK}">
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Green}"/>
</DataTrigger>
<DataTrigger Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.NG}">
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Red}"/>
</DataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsMouseOver}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsSelected}"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
解决方案 2:创建一个 behavior
并将其添加到基数 Style
,这将重新排序最终的 Style
。
问题:Behavior<TriggerCollection>
或 Behavior<Style>
不工作!
The type 'System.Windows.Style' must be convertible to 'System.Windows.DependencyObject' in order to use it as paramter 'T' in the generic class 'System.Windows.Interactivity.Behavior'
有人找到了如何在样式中使用 behavior
或如何更改继承的 Style
中的触发顺序的解决方案?
我通过 AttachedProperty
找到了解决方案。
我用最终 TriggerCollection
的索引缓存每个触发器。在呈现 DataGridRow
之后,else if (d is FrameworkElement frameworkElement)
是 true
并且 Style
被克隆并具有 Triggers
.
的新顺序
public static class TriggerAttachedBehavior
{
private static readonly Dictionary<Trigger, int> _Triggers = new Dictionary<Trigger, int>();
/// <summary>
/// Gets property value.
/// </summary>
/// <param name="attachedObj"></param>
/// <returns></returns>
public static int GetOderIndex(Trigger attachedObj)
{
return (int)attachedObj.GetValue(OderIndexProperty);
}
/// <summary>
/// Sets property value.
/// </summary>
/// <param name="attachedObj"></param>
/// <param name="value"></param>
public static void SetOderIndex(Trigger attachedObj, int value)
{
attachedObj.SetValue(OderIndexProperty, value);
}
/// <summary>
/// The <see cref="OderIndexProperty"/> DependencyProperty.
/// </summary>
public static readonly DependencyProperty OderIndexProperty = DependencyProperty.RegisterAttached("OderIndex", typeof(int), typeof(TriggerAttachedBehavior), new UIPropertyMetadata(-1, OderIndexChangedCallback));
/// <summary>
/// Occurs when OderIndexProperty has changed.
/// </summary>
/// <param name="d">Dependency object.</param>
/// <param name="args">Event arguments.</param>
private static void OderIndexChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
if (d is Trigger attachedObj)
{
_Triggers.Add(attachedObj, (int)args.NewValue);
}
else if (d is FrameworkElement frameworkElement)
{
// clone style with trigger lock
var newStyle = new Style(frameworkElement.Style.TargetType, frameworkElement.Style);
newStyle.Triggers.Clear();
// add all triggers except the base
foreach (TriggerBase triggerBase in frameworkElement.Style.Triggers)
{
if(_Triggers.Any(t => _Equals(t.Key, triggerBase)))
continue;
newStyle.Triggers.Add(triggerBase);
}
// add the base class triggers
foreach (int i in _Triggers.Values.OrderBy(t => t))
{
newStyle.Triggers.Add(_Triggers.First(t => t.Value == i).Key);
}
// apply new style
frameworkElement.Style = newStyle;
}
}
private static bool _Equals(TriggerBase x, TriggerBase y)
{
if (x.GetType() != y.GetType())
return false;
switch (x)
{
case DataTrigger dataTrigger:
return false;
case EventTrigger eventTrigger:
return false;
case MultiDataTrigger multiDataTrigger:
return false;
case MultiTrigger multiTrigger:
return false;
case Trigger trigger:
return trigger.Property.Name.Equals((y as Trigger).Property.Name);
}
return false;
}
}
<Style TargetType="DataGridRow" x:Key="DataGridRowSelectionStyle" BasedOn="{StaticResource DataGridRowDefaultStyle}">
<Setter Property="behaviors:TriggerAttachedBehavior.OderIndex" Value="0"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True" behaviors:TriggerAttachedBehavior.OderIndex="998">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsMouseOver}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True" behaviors:TriggerAttachedBehavior.OderIndex="999">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsSelected}"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
MultiDataTrigger
仅当 IsMouseOver 为 false 且 IsSelected 为 false 时, 才可用于根据状态值绘制行。附加条件(满足时)阻止 MultiDataTriggers 覆盖基础触发器:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowSelectionStyle}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.OK}"/>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="False"/>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Green}"/>
</MultiDataTrigger>
<MultiDataTrigger >
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.NG}"/>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="False"/>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Red}"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
我有一个基地 Style
- DataGridRowSelectionStyle
。在某些 DataGrids
上,我需要扩展此 Style
以添加 background
.
DataGridRowSelectionStyle
<Style TargetType="DataGridRow" x:Key="DataGridRowSelectionStyle">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsMouseOver}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsSelected}"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
行样式
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowSelectionStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.OK}">
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Green}"/>
</DataTrigger>
<DataTrigger Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.NG}">
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Red}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
因为Trigger
顺序,两个碱基Triggers
被覆盖,IsMouseOver
或IsSelected
不再触发
解决方案 1:扩展 RowStyle
。非常糟糕的解决方案,因为我不再需要我的基地 Style
..
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowSelectionStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.OK}">
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Green}"/>
</DataTrigger>
<DataTrigger Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.NG}">
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Red}"/>
</DataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsMouseOver}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsSelected}"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
解决方案 2:创建一个 behavior
并将其添加到基数 Style
,这将重新排序最终的 Style
。
问题:Behavior<TriggerCollection>
或 Behavior<Style>
不工作!
The type 'System.Windows.Style' must be convertible to 'System.Windows.DependencyObject' in order to use it as paramter 'T' in the generic class 'System.Windows.Interactivity.Behavior'
有人找到了如何在样式中使用 behavior
或如何更改继承的 Style
中的触发顺序的解决方案?
我通过 AttachedProperty
找到了解决方案。
我用最终 TriggerCollection
的索引缓存每个触发器。在呈现 DataGridRow
之后,else if (d is FrameworkElement frameworkElement)
是 true
并且 Style
被克隆并具有 Triggers
.
public static class TriggerAttachedBehavior
{
private static readonly Dictionary<Trigger, int> _Triggers = new Dictionary<Trigger, int>();
/// <summary>
/// Gets property value.
/// </summary>
/// <param name="attachedObj"></param>
/// <returns></returns>
public static int GetOderIndex(Trigger attachedObj)
{
return (int)attachedObj.GetValue(OderIndexProperty);
}
/// <summary>
/// Sets property value.
/// </summary>
/// <param name="attachedObj"></param>
/// <param name="value"></param>
public static void SetOderIndex(Trigger attachedObj, int value)
{
attachedObj.SetValue(OderIndexProperty, value);
}
/// <summary>
/// The <see cref="OderIndexProperty"/> DependencyProperty.
/// </summary>
public static readonly DependencyProperty OderIndexProperty = DependencyProperty.RegisterAttached("OderIndex", typeof(int), typeof(TriggerAttachedBehavior), new UIPropertyMetadata(-1, OderIndexChangedCallback));
/// <summary>
/// Occurs when OderIndexProperty has changed.
/// </summary>
/// <param name="d">Dependency object.</param>
/// <param name="args">Event arguments.</param>
private static void OderIndexChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
if (d is Trigger attachedObj)
{
_Triggers.Add(attachedObj, (int)args.NewValue);
}
else if (d is FrameworkElement frameworkElement)
{
// clone style with trigger lock
var newStyle = new Style(frameworkElement.Style.TargetType, frameworkElement.Style);
newStyle.Triggers.Clear();
// add all triggers except the base
foreach (TriggerBase triggerBase in frameworkElement.Style.Triggers)
{
if(_Triggers.Any(t => _Equals(t.Key, triggerBase)))
continue;
newStyle.Triggers.Add(triggerBase);
}
// add the base class triggers
foreach (int i in _Triggers.Values.OrderBy(t => t))
{
newStyle.Triggers.Add(_Triggers.First(t => t.Value == i).Key);
}
// apply new style
frameworkElement.Style = newStyle;
}
}
private static bool _Equals(TriggerBase x, TriggerBase y)
{
if (x.GetType() != y.GetType())
return false;
switch (x)
{
case DataTrigger dataTrigger:
return false;
case EventTrigger eventTrigger:
return false;
case MultiDataTrigger multiDataTrigger:
return false;
case MultiTrigger multiTrigger:
return false;
case Trigger trigger:
return trigger.Property.Name.Equals((y as Trigger).Property.Name);
}
return false;
}
}
<Style TargetType="DataGridRow" x:Key="DataGridRowSelectionStyle" BasedOn="{StaticResource DataGridRowDefaultStyle}">
<Setter Property="behaviors:TriggerAttachedBehavior.OderIndex" Value="0"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True" behaviors:TriggerAttachedBehavior.OderIndex="998">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsMouseOver}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True" behaviors:TriggerAttachedBehavior.OderIndex="999">
<Setter Property="Background" Value="{extensions:Theme Key=DataGrid_Row_IsSelected}"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
MultiDataTrigger
仅当 IsMouseOver 为 false 且 IsSelected 为 false 时, 才可用于根据状态值绘制行。附加条件(满足时)阻止 MultiDataTriggers 覆盖基础触发器:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowSelectionStyle}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.OK}"/>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="False"/>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Green}"/>
</MultiDataTrigger>
<MultiDataTrigger >
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding CurrentStatus}" Value="{x:Static production1:ProcessDataEval.NG}"/>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="False"/>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{extensions:Theme Key=DGLB_Red}"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>