I'm a true beginner in MVVM pattern. I'm trying to change the backgound of a grid on button's click. I have a xaml with a grid containing a button, and a ViewModel .cs from where i want to change the grid's background on button's click. Until there i just succeed to show up a MessageBox when i clicked...
.xaml code:
<Window x:Class="WpfSimple.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfSimple"
Title="MainWindow" Height="150" Width="370">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Button Content="Click"
Height="23"
HorizontalAlignment="Left"
Background="Gray"
Margin="75.944,47.465,0,0"
Name="btnClick"
VerticalAlignment="Top"
Width="203"
Command="{Binding ButtonCommand}"/>
<!--What is necessary to add for changing grid color ? Commandparameter ?-->
</Grid>
MainWindowViewModel.cs code:
namespace WpfSimple
{
class MainWindowViewModel
{
private ICommand m_ButtonCommand;
public ICommand ButtonCommand
{
get
{
return m_ButtonCommand;
}
set
{
m_ButtonCommand = value;
}
}
public MainWindowViewModel()
{
ButtonCommand=new RelayCommand(new Action<object>(ChangeBgColor));
}
public void ChangeBgColor(object obj)
{
/*HERE I WANT TO CHANGE GRID COLOR*/
}
}
}
Sorry for my bad english.
Best regards.
Fitst of all you should implement INotifyPropertyChanged in your ViewModel:
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then, add NotifyPropertyChanged() to your properties setter.
Ok. Next, add new Property with your grid background color to your ViewModel:
private Brush _gridBackground;
public Brush GridBackground
{
get { return _gridBackground; }
set
{
_gridBackground = value;
NotifyPropertyChanged();
}
}
And bind your grid's background to your property:
<Grid Background="{Binding GridBackground}">
Finally you can just change GridBackground in the command handler:
public void ChangeBgColor(object obj)
{
GridBackground = Brushes.Blue;
}
You should remember that it's a bad practice to add WPF-classes like Brush to your code. The better way is to use IValueConverter in XAML code and BCL classes in your ViewModel. For example, you can use enumeration in ViewModel and convert it to brush in ValueConverter.
Add new enum for your ViewModel's property:
public enum GridState { Valid, Invalid }
Change property type:
private GridState _gridBackground;
public GridState GridBackground
{
get { return _gridBackground; }
set
{
_gridBackground = value;
NotifyPropertyChanged();
}
}
Add new class with value converter
public class GridStateToBackgroundColorConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
GridState val = (GridState) value;
if(val == GridState.Valid)
return Brushes.Green;
return Brushes.Red;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
}
Add new static resource to your control
<UserControl.Resources>
<converters:GridStateToBackgroundColorConverter x:Key="gridStateToBackgroundColorConverter" />
</UserControl.Resources>
Update binding to your property
<Grid Background="{Binding GridBackground, Converter={StaticResource gridStateToBackgroundColorConverter}">
If you want to change the grid background color then you can use command parameter. You can pass any UI control as Command parameter. In your case pass grid to access grid in your view model.
Give the name to your grid and use that name to use as command parameter.
For this you need to implement the code like this:
<Window x:Class="WpfSimple.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfSimple"
Title="MainWindow" Height="150" Width="370">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid Name="grid">
<Button Content="Click"
Height="23"
HorizontalAlignment="Left"
Background="Gray"
Margin="75.944,47.465,0,0"
Name="btnClick"
VerticalAlignment="Top"
Width="203"
Command="{Binding ButtonCommand}"
CommandParameter="{Binding Elementname="grid"}"/>
</Grid>
After making this change to the .xaml file. Implement Parameterized Relay Command to use this passed Grid to use in your Viewmodel file.
To Implement Parameterized Relay Command Try to Implement following code:
private ICommand m_ButtonCommand;
public ICommand ButtonCommand
{
get
{
return m_ButtonCommand;
}
set
{
m_ButtonCommand = value;
}
}
public MainWindowViewModel()
{
ButtonCommand=new RelayCommand<Grid>(ChangeBgColor);
}
public void ChangeBgColor(Grid grid)
{
if(grid!=null)
grid.Background = Brushes.Red; //Any color you want to change.
}
I hope this will work. Thank you.