3
votes

I have this code in my xaml which says to color my button when I hover my mouse and click my mouse over the button.

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

This works all well and good, but I find that as soon as I change the Background color in code behind, the above MouseOver and MouseDown triggers don't fire anymore.

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

I'm quite new to WPF so I'm not sure what's going wrong.

Edit:

So to give some more information, my control above is a RowHeaderButton, i.e the row header to a grid. Each row in the grid has it's own row header button. So when the user hovers over or clicks it, it should change from white to the specified SolidColorBrush above.

In the code behind of another control, DataGrid.xaml.cs, I have the below code (simplified) which will change the color of the row header when when a cell in the same row of the grid is selected or not.

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

I don't have a ViewModel for this.

2
If you create a simple ViewModel the code will get better, easier to change GUI without directly changing the GUI elements, but changing the properties that are Binded with them.Tony

2 Answers

2
votes

The triggers are firing, but their setters are being overridden.

This is due to Dependency Property Value Precendence. If the Background property is set programmatically or as an attribute in the XAML, that value will override anything value any style setter gives it. In general, this is desirable behavior: You want to be able to override what the style does on an individual control.

The solution to this is to do all of your background brush changes in style triggers. Your code behind must have some reason for setting the background brush when it does. Whatever that is, find a way to do it with a trigger. Set a property on the viewmodel and write a trigger on that property.

If you need help translating that high level abstraction into your own code, please share enough code for me to understand why and where the codebehind is setting the Background, and what (if anything) you have for a viewmodel.

1
votes

I solved the issue by creating a new Dependancy Property and binding it to a data trigger.

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

In my xaml I have:

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

And in my code behind I set the value using:

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

Now my button hover and button click events are not overridden.