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! :)