1

I am trying to learn WPF/MVVM and for educational reason I create a simple application. I have some issues trying to implement a Command Object.

When a button control is clicked I want the background color of the Grid change to yellow using a Command Object. There are a lot of stuff about how to do this, but I want to do it with the clean way. Generally I want to achieve a loose coupling between View, ViewModel and the Command Object in order to test those classes.

Also i do not want to use some Libraries like Prism because I have the need to fully understand MVVM first.

I have a code sample but of course it does not have functionality. Just represented it for convenience reason.

My view XAML

<Window x:Class="Calendar.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Calendar"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="480">

<Grid Background="{Binding BackgroundColour}" Margin="0,0,2,0">
    <Button Margin="197,247,200,-239" Grid.Row="3" Grid.ColumnSpan="2" Command="{Binding SubmitCommand}">Color</Button>
</Grid>

My ModelView class

public class MainWindowViewModel : INotifyPropertyChanged {

    //Command part
    ICommand SubmitCommand;
    public MainWindowViewModel(ICommand command) {
        SubmitCommand = command;
    }

    //Data Binding part
    public event PropertyChangedEventHandler PropertyChanged;
    private Brush backgroundColour = (Brush)new BrushConverter().ConvertFromString("Red");
    public Brush BackgroundColour {
        get { return this.backgroundColour; }
        set {
            if (value != this.backgroundColour) {
                this.backgroundColour = value;
                var handler = this.PropertyChanged;
                if (handler != null) {
                    handler(this, new PropertyChangedEventArgs("BackgroundColour"));
                }
            }
        }

(it also has a data binding part but it does not have to do with my issue)

3 Answers 3

2

You would like not to have anything related to windows like colors(Brushes or Brush) in the viewmodel. Refer my below code.

<Window x:Class="MVVMNav_Learning.Window1"
    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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MVVMNav_Learning"
    mc:Ignorable="d"
    Title="Window1" Height="300" Width="300">
<Window.Resources>
    <local:ColorConverterConverter x:Key="ColorConverterConverter"></local:ColorConverterConverter>
</Window.Resources>
<Grid>
    <Grid Background="{Binding BackgroundColour,Converter={StaticResource ColorConverterConverter}}" Margin="0,0,2,0">
        <Button Margin="50"  Command="{Binding SubmitCommand}">Color</Button>
    </Grid>
</Grid>

 public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        this.DataContext = new ViewModel();
    }
}

public class ViewModel:INotifyPropertyChanged
{
    private MyColor backColor;

    public MyColor BackgroundColour
    {
        get { return backColor; }
        set { backColor = value; OnPropertyChanged("BackgroundColour"); }
    }

    public ICommand SubmitCommand { get; set; }

    public ViewModel()
    {
        BackgroundColour = MyColor.Red;
        SubmitCommand = new BaseCommand(Execute);
    }

    public void Execute(object parameter)
    {
        BackgroundColour = MyColor.Yellow;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

public enum MyColor
{
    Red,
    Green,
    Yellow
}

public class BaseCommand : ICommand
{
    private Action<object> _method;
    public event EventHandler CanExecuteChanged;

    public BaseCommand(Action<object> method)
    {
        _method = method;
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        _method.Invoke(parameter);
    }
}

public class ColorConverterConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        MyColor color = (MyColor)value;
        switch (color)
        {
            case MyColor.Red:
                return Brushes.Red;
            case MyColor.Green:
                return Brushes.Green;
            case MyColor.Yellow:
                return Brushes.Yellow;
            default:
            {
                return Brushes.Red;
            }
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Sign up to request clarification or add additional context in comments.

8 Comments

Subeamanian your provided code have a lot of stuff, give me some time to take a look and i will come back with questions.
at this line SubmitCommand = new BaseCommand(Execute); where it exists at ViewModel constructor, how the ViewModel know about the Execute dependency?
Refer the basecommand class, it is a common implemtation of ICommand, where you dont have to used a separate class to implement your commands. Suppose in a page if you have 5 button you dont have to create 5 classes to handle the click logic and also you can avoid passing viewmodel info to the command class. BaseCommand will have a action which will be invoking a method in your viewmodel. It is a slick way of handling commands.
Can I test ViewModel class with that new inside constructor?
Yes, But you need to change the implemtation of BaseCommand to handle the CanExecute.
|
0

You need to create a public Property for the ICommand SubmitCommand and you can use a private DelegateCommand in its getter/setter.

Comments

0

You are not very clearly stating your question, but I gamble it to be: How to configure the command parameter for the viewmodel's constructor to have it change the backgroundcolour?

Commands do their work by having them implement ICommand.Execute(Object) So basically you want to have the command object you pass to the constructor to have a method like:

void Execute(object parameter)
    {
        viewModel.BackGroundColor=Brushes.Yellow;
    }

This is awkward: the command is passed from outside the viewmodel, but it must have a reference to it to change its back colour. You may want to rethink your design.

Moreover: for the databinding engine to see the SubmitChangedCommand it must be a property:

public ICommand SubmitChangesCommand {get;set;}

3 Comments

ok, so lets ask again the question with a different form. How a button can change the Grid background color when it's clicked?
@dios231 How a button can change the Grid background color when it's clicked using a command ?
@dios231 So: add the question to your post!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.