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>
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.