Question

I have a custom button extending from Button and in the constructor I want to add IsMouseOver property trigger to change color;

Please, no suggestion "you should do in xaml..." that is not the question.

I am trying the below but I have errors:

    public powerButton()
    {
        if (DesignerProperties.GetIsInDesignMode(this) || !DesignerProperties.GetIsInDesignMode(this))
        {
             ApplyBackgroundStyle();
        }

        /*
        Style style = new Style();
        style.TargetType = typeof(Button);
        DataTrigger trigger = new DataTrigger();
        trigger.Value = "OK";
        //set binding
        trigger.Binding = new Binding() { Path = new PropertyPath("Content"), RelativeSource = RelativeSource.Self };
        Setter setter = new Setter();
        setter.Property = Button.IsMouseOverProperty;
        setter.Value = Brushes.Green;
        trigger.Setters.Add(setter);
        //clear the triggers
        style.Triggers.Clear();
        style.Triggers.Add(trigger);
        this.Style = style;*/
    }
Was it helpful?

Solution

Based on your question, I think you're looking for something like this:

Style style = new Style();
style.TargetType = typeof(Button);
MultiDataTrigger trigger = new MultiDataTrigger();
Condition condition1 = new Condition();
condition1.Binding = new Binding() { Path = new PropertyPath("Content"), RelativeSource = RelativeSource.Self };
condition1.Value = "OK";
Condition condition2 = new Condition();
condition2.Binding = new Binding(){Path = new PropertyPath("IsMouseOver"), RelativeSource = RelativeSource.Self};
condition2.Value = true;
Setter setter = new Setter();
setter.Property = Button.ForegroundProperty;
setter.Value = Brushes.Green;
trigger.Conditions.Add(condition1);
trigger.Conditions.Add(condition2);
trigger.Setters.Add(setter);
style.Triggers.Clear();
style.Triggers.Add(trigger);
this.Style = style;

Which will cause the Foreground color of the Button to be Green when the two conditions are met:

1 - the Button.Content equals "OK"

2 - the mouse is over the Button.

Which can be expressed with the following XAML:

<Button Content="OK">
    <Button.Style>
        <Style TargetType="Button">
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Content, RelativeSource={RelativeSource Self}}" Value="OK"/>
                        <Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True"/>
                    </MultiDataTrigger.Conditions>

                    <Setter Property="Foreground" Value="Green"/>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

With no need whatsoever to inherit from WPF UI elements and create a custom button simply to set visual Styles or visual behavior.

Subclassing WPF UI Elements is discouraged because it reduces maintainability and it's completely unneeded. The WPF UI model is based on Lookless controls, which means that a Controls visual appearance is completely separate and independent from it's functionality. As a general rule, you only subclass WPF UI elements if you're going to define new functionality, as opposed to changing it's appearance, which can be done thru WPF's built-in mechanisms such as Styles and Templates.

It is strongly recommended that you use a proper WPF approach in WPF as opposed to a winforms approach. The above code shows how convoluted and cumbersome it is to procedurally create the object graph in C# code, while it is simpler and much cleaner in XAML, since there is no "condition1, condition2", etc needless boilerplate.

If your developers are not familiar with XAML, there are tons of XAML tutorials in the Web, and notoriously MSDN has comprehensive documentation on the subject.

Down the line, you will find critical issues with your current approach, due to the complexity of the WPF Visual Tree and concepts such as UI Virtualization which make it really hard to operate with the UI in a procedural fashion.

It is also strongly recommended that you use an MVVM approach and proper DataBinding as opposed (again) to a traditional, winforms-like approach in WPF.

Again, I cannot emphasize enough that approaching WPF the way you're doing here only brings pain, torture, and failure, and a huge amount of completely unnecessary, unmaintainable, non-scalable code prone to all sorts of unexpected errors which can't be easily resolved

OTHER TIPS

It looks like a typo:

Setter setter = new Setter();
setter.Property = Button.BackgroundProperty; // Here it was Button.IsMouseOverProperty
setter.Value = Brushes.Green;
trigger.Setters.Add(setter);

You are trying to set the Brushes.Green value for IsMouseOver property, and it does not work because:

  • The IsMouseOver is readonly property

  • The Brushes.Green value applicable for properties that take a Brush, such as the Background and Foreground properties

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top