【问题标题】:WPF XAML datatrigger fails to fire after programmatically changing property value C#以编程方式更改属性值 C# 后 WPF XAML 数据触发器无法触发
【发布时间】:2017-10-31 13:44:41
【问题描述】:

我的 xaml 中有这段代码,当我将鼠标悬停并在按钮上单击鼠标时,它会为按钮着色。

<Border x:Class="DatasetGrid.RowHeaderButton"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" MinWidth="30" Width="Auto">
<Border.Resources>
        <SolidColorBrush x:Key="ButtOverBrush" Color="#53C3D5" Opacity="0.2"></SolidColorBrush>
        <SolidColorBrush x:Key="ButtPressedBrush" Color="#53C3D5" Opacity="0.5"></SolidColorBrush>
</Border.Resources>
    <Border.Style>
        <Style TargetType="Border">
            <Setter Property="Background" Value="Transparent"></Setter>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="{StaticResource ButtOverBrush}"></Setter>
                </Trigger>
                <DataTrigger Binding="{Binding IsMouseDown, RelativeSource={RelativeSource Self}}" Value="True">
                    <Setter Property="Background" Value="{StaticResource ButtPressedBrush}"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Border.Style>
</Border>

这一切都很好,但我发现只要我在后面的代码中更改背景颜色,上面的 MouseOver 和 MouseDown 触发器就不会再触发了。

RowHeaderButton rhb = RowHeadersColumn.VisibleRowHeaders[cell.CellInfo.RowIndex];
rhb.Background = new SolidColorBrush(Color.FromArgb(100, 83, 195, 213));

我对 WPF 很陌生,所以我不确定出了什么问题。

编辑:

所以为了提供更多信息,我上面的控件是一个 RowHeaderButton,即网格的行标题。网格中的每一行都有自己的行标题按钮。所以当用户悬停或点击它时,它应该会从白色变为上面指定的 SolidColorBrush。

在另一个控件后面的代码中,DataGrid.xaml.cs,我有以下代码(简化),它将在选择与网格的相同行中的单元格时更改行标题的颜色。

void UpdateSelectedCells() {            

    foreach (Cell cell in VisibleColumns.SelectMany(c => c.VisibleCells))
        {
            int cellRowIndex = cell.CellInfo.RowIndex;
            cell.IsSelected = SelectedCells.Contains(cell.CellInfo);

            foreach (RowHeaderButton rhb in RowHeadersColumn.VisibleRowHeaders)
            {
                int rowHeaderIndex = Convert.ToInt16(rhb._default.Text) - 1;

                if (cellRowIndex == rowHeaderIndex)
                {
                    if (cell.IsSelected)
                    {
                        rhb.Background = new SolidColorBrush(Color.FromArgb(100, 83, 195, 213));
                    }
                    else
                    {
                        bool rowselected = false;

                        //need to check if any other cell in the row is selected, if not then color row header white
                        foreach (CellInfo celll in SelectedCells)
                        {

                            if (celll.RowIndex == cellRowIndex)
                            {
                                rowselected = true;
                                break;
                            }
                        }

                        if (rowselected == false)
                            rhb.Background = Brushes.White;
                    }
                }
            }
    }
}

我没有这个的 ViewModel。

【问题讨论】:

  • 如果您创建一个简单的 ViewModel,代码会变得更好,更容易更改 GUI,无需直接更改 GUI 元素,而是更改与它们绑定的属性。

标签: c# wpf xaml


【解决方案1】:

触发器正在触发,但它们的设置器正在被覆盖。

这是由于Dependency Property Value Precendence。如果 Background 属性以编程方式设置或作为 XAML 中的属性设置,则该值将覆盖任何样式设置器为其提供的任何值。通常,这是一种理想的行为:您希望能够覆盖样式对单个控件的作用。

解决方案是在样式触发器中执行所有背景画笔更改。您背后的代码必须有一些理由来设置背景画笔。不管是什么,找到一种使用触发器的方法。在视图模型上设置一个属性并在该属性上编写一个触发器。

如果您在将高级抽象转换为您自己的代码时需要帮助,请分享足够多的代码让我了解代码隐藏设置背景的原因和位置,以及您对视图模型有什么(如果有的话)。

【讨论】:

  • 感谢您的回答,现在说得通了。我将对上面的代码进行编辑,以便您更容易理解我在做什么/试图实现什么。
  • 我在主帖中添加了更多信息。我不使用视图模型,后面的代码是针对 DataGrid.xaml.cs 而上面的 XAML 在 RowHeaderButton.xaml
  • @nerdalert 如果该行中有任何个选定单元格,您是否只是为行标题单元格着色?
  • 是的,如果选择了行中的任何单元格,我会为行标题着色。它表示该行处于焦点位置。我可能应该进一步简化代码,我也有代码来为列标题着色,所以它可能会造成混淆。这种情况下不需要该代码。
  • 是的 RowHeaderButton 是我自己的类。 DataGrid 也是自定义编写的。无论如何,我相信我通过考虑您最初的建议来解决这个问题,即为是否选择单元格创建一个新属性,并根据它为行着色
【解决方案2】:

我通过创建一个新的依赖属性并将其绑定到数据触发器解决了这个问题。

public bool IsCellSelected
    {
        get { return (bool)GetValue(IsCellSelectedProperty); }
        set { SetValue(IsCellSelectedProperty, value); }
    }
    public static readonly DependencyProperty IsCellSelectedProperty =
        DependencyProperty.Register("IsCellSelected", typeof(bool), typeof(RowHeaderButton), new PropertyMetadata(null));

在我的 xaml 中,我有:

<DataTrigger Binding="{Binding IsCellSelected, RelativeSource={RelativeSource Self}}" Value="True">
     <Setter Property="Background" Value="{StaticResource ButtPressedBrush}"></Setter>
</DataTrigger>

在我后面的代码中,我使用以下方法设置值:

RowHeaderButton rhb = RowHeadersColumn.VisibleRowHeaders[cell.CellInfo.RowIndex];
rhb.IsCellSelected = true; //or false

现在我的按钮悬停和按钮点击事件不会被覆盖。

【讨论】:

    猜你喜欢
    • 2011-09-06
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 2018-08-08
    • 2016-02-06
    相关资源
    最近更新 更多