Home > other >  When binding a button to a command it's styling (background) dissapears
When binding a button to a command it's styling (background) dissapears

Time:10-29

Im working on the UI for my application. Currently I'm experiencing a problem where when I bind my button command propperty to a relay command the background of the color is reset to it's default.

My XAML code:

<Window
    AllowsTransparency="True"
    Height="450"
    ResizeMode="NoResize"
    Title="MainWindow"
    Width="800"
    WindowStyle="None"
    mc:Ignorable="d"
    x:Class="ChatApplicatie.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:ChatApplicatie"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:viewModel="clr-namespace:ChatApplicatie.MVVM.ViewModel"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Window.DataContext>
        <viewModel:MainViewModel/>
    </Window.DataContext>

    <Border BorderThickness="5" CornerRadius="25">
        <Border.BorderBrush>
            <LinearGradientBrush EndPoint="1,1" StartPoint="0,0">
                <GradientStop Color="{StaticResource winBorderColor1}" Offset="0.0" />
                <GradientStop Color="{StaticResource winBorderColor2}" Offset="0.75" />
                <GradientStop Color="{StaticResource winBorderColor3}" Offset="1.0" />
            </LinearGradientBrush>
        </Border.BorderBrush>
        <Border.Background>
            <LinearGradientBrush EndPoint="1,0" StartPoint="0,1">
                <GradientStop Color="{StaticResource primaryBackColor1}" Offset="0.0" />
                <GradientStop Color="{StaticResource primaryBackColor2}" Offset="0.75" />
            </LinearGradientBrush>
        </Border.Background>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="1*" />
                <RowDefinition Height="13*" />
            </Grid.RowDefinitions>
            <Label
                Content="Chat Applicatie"
                FontSize="15"
                FontWeight="Bold"
                Foreground="SlateGray"
                Margin="20,0" />
            <StackPanel
                HorizontalAlignment="Right"
                Margin="0,0,15,0"
                Orientation="Horizontal">
                <Button
                    Background="Transparent"
                    BorderThickness="0"
                    Click="ButtonMinimize_Click"
                    Content="⎯"
                    Foreground="Gray"
                    Height="20"
                    Width="20" />
                <Button
                    Background="Transparent"
                    BorderThickness="0"
                    Click="ButtonClose_Click"
                    Content="╳"
                    FontSize="10"
                    Foreground="Gray"
                    Height="20"
                    Width="20" />
            </StackPanel>
            <Grid Grid.Row="1">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="3*" />
                </Grid.ColumnDefinitions>
                <DockPanel Grid.Column="0">
                    <TextBox
                        DockPanel.Dock="Top"
                        Foreground="White"
                        Height="25"
                        Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}">
                        <TextBox.Background>
                            <SolidColorBrush Color="White" Opacity="0.1" />
                        </TextBox.Background>
                    </TextBox>
                    <!--The button from which im trying to change the color-->
                    <Button
                        Background="Red"
                        Content="Connect"
                        DockPanel.Dock="Top"
                        Command="{Binding ConnectToServerCommand}"
                        Height="25">
                        <Button.Resources>
                            <Style TargetType="Border">
                                <Setter Property="CornerRadius" Value="5" />
                            </Style>
                        </Button.Resources>
                    </Button>
                    <ListView
                        Background="{x:Null}"
                        Foreground="White"
                        ItemsSource="{Binding Users}">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Username}" />
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </DockPanel>
                <Grid Grid.Column="1">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="8*" />
                        <RowDefinition Height="1*" />
                    </Grid.RowDefinitions>
                    <ListView
                        Background="{x:Null}"
                        Foreground="White"
                        Height="Auto"
                        ItemsSource="{Binding Messages}" />

                    <StackPanel Grid.Row="1" Orientation="Horizontal">
                        <TextBox
                            Text="{Binding Message, UpdateSourceTrigger=PropertyChanged}"
                            VerticalContentAlignment="Center"
                            Width="520">
                            <TextBox.InputBindings>
                                <KeyBinding Command="{Binding SendMessageCommand}" Key="Enter" />
                            </TextBox.InputBindings>
                            <TextBox.Resources>
                                <Style TargetType="Border">
                                    <Setter Property="CornerRadius" Value="6" />
                                </Style>
                            </TextBox.Resources>
                        </TextBox>
                        
                        <Button
                            Command="{Binding SendMessageCommand}"
                            Content="Send"
                            Width="55">
                            
                            <Button.Resources>
                                <Style TargetType="Border">
                                    <Setter Property="CornerRadius" Value="5" />
                                </Style>
                            </Button.Resources>
                        </Button>
                    </StackPanel>

                </Grid>
            </Grid>
        </Grid>

    </Border>
</Window>

enter image description here

The from the viewmodel in which the buttons command is bound.

using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using ChatApplicatie.MVVM.CoreComponents;
using ChatApplicatie.MVVM.Model;
using ChatApplicatie.Net;

namespace ChatApplicatie.MVVM.ViewModel;

public class MainViewModel
{
    public ObservableCollection<UserModel> Users { get; set; }
    public ObservableCollection<string> Messages { get; set; }
    public RelayCommand ConnectToServerCommand { get; set; }
    public RelayCommand SendMessageCommand { get; set; }
    public string Username { get; set; }
    public string Message { get; set; }
    
    private Server _server;
    public MainViewModel()
    {
        Users = new ObservableCollection<UserModel>();
        Messages = new ObservableCollection<string>();
        _server = new Server();
        _server.connectedEvent  = UserConnected;
        _server.msgReceivedEvent  = MessageReceived;
        _server.userDisconnectEvent  = RemoveUser;
        ConnectToServerCommand = new RelayCommand(o => _server.ConnectToServer(Username), o => !string.IsNullOrEmpty(Username));
        SendMessageCommand = new RelayCommand(o => _server.SendMessageToServer(Message), o => !string.IsNullOrEmpty(Message));
    }

    private void RemoveUser()
    {
        var uid = _server.PacketReader.ReadMessage();
        var user = Users.Where(x => x.UID == uid).FirstOrDefault();
        Application.Current.Dispatcher.Invoke(() => Users.Remove(user));
    }

    private void MessageReceived()
    {
        var msg = _server.PacketReader.ReadMessage();
        Application.Current.Dispatcher.Invoke(() => Messages.Add(msg));
    }

    private void UserConnected()
    {
        var user = new UserModel
        {
            Username = _server.PacketReader.ReadMessage(),
            UID = _server.PacketReader.ReadMessage(),
        };
        if (!Users.Any(x => x.UID == user.UID))
        {
            Application.Current.Dispatcher.Invoke(() => Users.Add(user));
        }
    }
}

I don't fully understand how the binding affects the other properties of the button and im open for any tips or help.

  • Changing the background property through standard xaml

  • Changing the backgroudn property through the style attribute with setters

  • Removing the command binding displays the color in the button.

CodePudding user response:

The color you set in the button's properties is used for the button's normal state.

In your case, after connecting the command, the button will be disabled (IsEnabled=false), since you do not pass a parameter to the command. And the command method o => !string.IsNullOrEmpty(Username) requires a non-empty string for the command.

And the colors of the button other than the normal state are set by constants in the button template. Therefore, it is impossible to change them without changing the button template.

In your case, to enable the button, you need to set the command parameter binding.

    <Button
            Background="Red"
            Content="Connect"
            DockPanel.Dock="Top"
            Command="{Binding ConnectToServerCommand}"
            CommandParameter="{Binding UserName}"
            Height="25">
        <Button.Resources>
            <Style TargetType="Border">
                <Setter Property="CornerRadius" Value="5" />
            </Style>
        </Button.Resources>
    </Button>

When you enter UserName, the button will turn on and take on the colors you set.

The RelayCommand implementation code also matters. In WPF, a Command must automatically subscribe to CommandManager.RequerySuggested.
Otherwise, the button may not always be automatically enabled when the parameter is changed.

I'm also worried about the implementation of mutable properties in the MainViewModel.
If a property has a setter, then it MUST have a built-in property change notification through the INotifyPropertyChanged.PropertyChanged event.
You don't have it. Therefore, changes to the properties of the MainViewModel may not always automatically update the properties bound to them.

  • Related