1

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;*/
    }
RollRoll
  • 8,133
  • 20
  • 76
  • 135
  • most of our developers are not familiar with xaml configuration but are very strong OOP oriented people, doing in code is our option to save time in development and better maintanance. I understand you are very passionate about xaml and most people use that for custom control styiling, we are exception cuz we believe it is our best option and clr allows us to do so. I can happily create another topic about the "way-to-go" which is not here. – RollRoll Apr 22 '14 at 17:54
  • sorry, if you don't know XAML (and refuse to learn it) then go back to winforms. the [**WPF Mentality**](http://stackoverflow.com/a/15684569/643085) is really completely different from the winforms approach, and WPF is not intended to be used this way. You'll regret this decision in the future. using WPF with winforms approach is **never** the "best option" for anyone. – Federico Berasategui Apr 22 '14 at 18:00
  • BTW, there is no such thing as "XAML configuration". You seem to completely misunderstand the declarative nature of XAML. It's not "configuration", it is a declarative language that allows you to declare and object graph in a much cleaner way than the horrid code you posted here. – Federico Berasategui Apr 22 '14 at 18:02
  • thanks for the suggestion, but again, this is not the point of the question – RollRoll Apr 22 '14 at 18:05
  • let me know when you need help completely refactoring and redoing your failed project from scratch in (proper) WPF. – Federico Berasategui Apr 22 '14 at 18:06

2 Answers2

3

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

Community
  • 1
  • 1
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
0

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

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
  • I got you, it is clear now I am not using the correct, way. But in your example I don't see how to approach IsMouseOver property – RollRoll Apr 22 '14 at 18:06
  • @ThePoet: I do not understand your conditions for changing the button background. What should be the main (`IsMouseOver="True"` or `Content="OK"`) condition? – Anatoliy Nikolaev Apr 22 '14 at 18:10