Home > OS >  WPF STYLES - button with connected boolean variable changing background collor
WPF STYLES - button with connected boolean variable changing background collor

Time:12-06

I would like to achieve such configuration: button style in my WPF app - I have a process/windows service with hundreds of BOOL variables which I need to change a state from my WPF app/UI. Those variables can be controlled also by other apps.

So I have created a model/class in my WPFapp which is querying those variables and updating my internal variables states based on data. This is working fine.

I have such WORKING objects in my WPF View (for test)


<Button Width="30" Height="30">
            <Button.Resources>
                <Style TargetType="Button">
                    <Setter Property="Background"
                            Value="Gray" />

                    <Style.Triggers>

                        <DataTrigger Binding="{Binding LifeBitVariable}" Value="True">
                            <Setter Property="Background" Value="Green" />
                        </DataTrigger>

                        <DataTrigger Binding="{Binding LifeBitVariable}" Value="False">
                            <Setter Property="Background" Value="Red" />
                        </DataTrigger>
                    </Style.Triggers>

                </Style>
            </Button.Resources>
        </Button>

And this in my VM:

public bool LifeBitVariable
        {
            get { return communication.LifeBitVariable; }
            set { communication.LifeBitVariable = value; NotifyPropertyChanged(); }
        }

How to change this to the style? I would like to have a button style and in my View call this style and just connect a variable from my ViewModel (each button will have different variable connected - this button style will be used in multiple View with multiple variables from ViewModel)

P.S. I would like to have this style in Resource Dictionary call later in APP.xaml and View by Style="{StaticResource MyStyle}".

CodePudding user response:

You can achieve this in multiple ways, here are two I can think of at the moment:

Option 1: Use a style Button within a DataTemplate (applicable if you have the items in a collection)

<ItemsControl ItemsSource="{Binding ConfigurationItems}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Width="30" Height="30">
                <Button.Resources>
                    <Style TargetType="Button">
                        <Setter Property="Background" Value="Gray" />

                        <Style.Triggers>
                            <DataTrigger Binding="{Binding IsActive}" Value="True">
                                <Setter Property="Background" Value="Green" />
                            </DataTrigger>

                            <DataTrigger Binding="{Binding IsActive}" Value="False">
                                <Setter Property="Background" Value="Red" />
                            </DataTrigger>
                        </Style.Triggers>

                    </Style>
                </Button.Resources>
            </Button>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Option 2: A custom control that inherits from Button

ConfigurationButton.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace ConfigButtons;

public class ConfigurationButton : Button
{
    //define a bindable property
    public static readonly DependencyProperty IsActiveProperty =
        DependencyProperty.Register(
          name: nameof(IsActive),
          propertyType: typeof(bool),
          ownerType: typeof(ConfigurationButton), 
          new FrameworkPropertyMetadata(defaultValue: false, propertyChangedCallback: IsActivePropertyChangedCallback));

    public bool IsActive
    {
        get => (bool)GetValue(IsActiveProperty);
        set => SetValue(IsActiveProperty, value);
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        //update the background color when first rendered
        UpdateBackgroundColor(IsActive);
    }

    public static void IsActivePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if(d is not ConfigurationButton configurationButton || e.NewValue is not bool isActive)
        {
            return;
        }

        //update background color whenever the IsActive property changes
        configurationButton.UpdateBackgroundColor(isActive);
    }

    private void UpdateBackgroundColor(bool isActive)
    {
        Background = new SolidColorBrush(isActive ? Colors.Green : Colors.Red);
    }
}

Usage:

<Window
    x:Class="ConfigButtons.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:ConfigButtons"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <WrapPanel>
        
        <!--This button will be RED-->
        <local:ConfigurationButton Content="OFF" />
        
        <!--And this one GREEN-->
        <local:ConfigurationButton Content="ON" IsActive="True" />
        
    </WrapPanel>
</Window>

I'm sure there are more ways to do this, I'm curious to see other answers.

CodePudding user response:

Ok, I found some guidance at this topic CLICK

So my final solution looks like this:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Style x:Key="MyButton"
       TargetType="Button">

    <Setter Property="Width"
            Value="100"/>
    <Setter Property="Height"
            Value="30"/>
    <Setter Property="Background"
            Value="#FFDECFCF" />

    <Style.Triggers>

        <DataTrigger Binding="{Binding}" Value="True">
            <Setter Property="Background" Value="Green"/>
        </DataTrigger>

        <DataTrigger Binding="{Binding}" Value="False">
            <Setter Property="Background" Value="Red"/>
        </DataTrigger>

    </Style.Triggers>
</Style>

and In my View:

<Button Style="{StaticResource MyButton}"
            DataContext="{Binding LifeBitVariable}" />

Everything is working as I was expecting! :)

  • Related