代码之家  ›  专栏  ›  技术社区  ›  Dominic Jonas

更改BasedOn/inherited样式中的触发器顺序

  •  1
  • Dominic Jonas  · 技术社区  · 6 年前

    我有一个基地 Style - DataGridRowSelectionStyle . 在一些 DataGrids 我需要延长这个时间 风格 background .

    数据网格行选择样式

    <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 . 很糟糕的解决方案,因为我不需要我的基地 风格 不再。。

    <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 把它加到底座上 风格 会重新安排决赛 风格 . 问题: Behavior<TriggerCollection> Behavior<Style> 不工作!

    类型“System.Windows.Style”必须可转换为“System.Windows.DependencyObject”,才能将其用作泛型类“System.Windows.Interactivity.Behavior”中的参数“T”


    有人找到了一个解决方案如何使用 行为 在样式中或如何更改继承的 风格 ?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Dominic Jonas    6 年前

    我用一个 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>
    
        2
  •  0
  •   ASh aminescm    6 年前

    MultiDataTrigger 可用于根据行的状态值绘制行 只有当 IsMouseOver是错误的,IsSelected是错误的。其他条件(当满足这些条件时)阻止多数据触发器重写基本触发器:

    <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>