Aaron Rumford
Aaron Rumford

Reputation: 586

Dual binding on Checkbox

I have a WPF application using MVVM. I have the IsChecked value bound to a boolean on my model instance on my ViewModel. I also need to bind a method on the ViewModel to the Checked and Unchecked events. (This is so I can track unsaved changes and change the background to give my users visual indication of the need to save. I tried:

<CheckBox 
    Content="Enable" 
    Margin="5" 
    IsChecked="{Binding Enabled}" 
    Checked="{Binding ScheduleChanged}" 
    Unchecked="{Binding ScheduleChanged}"
    />

But I get a 'Provide value on 'System.Windows.Data.Binding' threw an exception.' error. Advice?

Here is the Model I am working with:

    public class Schedule : IEquatable<Schedule>
{
    private DateTime _scheduledStart;
    private DateTime _scheduledEnd;
    private bool _enabled;
    private string _url;
    public DateTime ScheduledStart
    {
        get { return _scheduledStart; }
        set
        {
            _scheduledStart = value;
        }
    }
    public DateTime ScheduledEnd
    {
        get { return _scheduledEnd; }
        set
        {
            if(value < ScheduledStart)
            {
                throw new ArgumentException("Scheduled End cannot be earlier than Scheduled Start.");
            }
            else
            {
                _scheduledEnd = value;
            }
        }
    }
    public bool Enabled
    {
        get { return _enabled; }
        set { _enabled = value; }
    }
    public string Url
    {
        get { return _url; }
        set { _url = value; }
    }

    public bool Equals(Schedule other)
    {
        if(this.ScheduledStart == other.ScheduledStart && this.ScheduledEnd == other.ScheduledEnd 
            && this.Enabled == other.Enabled && this.Url == other.Url)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

My viewModel contains a property that has an ObservableCollection. An ItemsControl binds to the collection and generates a list. So my ViewModel sort of knows about my Model instance, but wouldn't know which one, I don't think.

Upvotes: 0

Views: 167

Answers (2)

RQDQ
RQDQ

Reputation: 15569

You should be able to just handle this in the setter for Enabled...

public class MyViewModel : ViewModelBase
{

    private bool _isDirty;
    private bool _enabled;

    public MyViewModel()
    {
        SaveCommand = new RelayCommand(Save, CanSave);
    }

    public ICommand SaveCommand { get; }

    private void Save() 
    {
       //TODO: Add your saving logic
    }

    private bool CanSave()
    {
        return IsDirty;
    }

    public bool IsDirty
    {  
       get { return _isDirty; }
       private set 
       {
           if (_isDirty != value) 
           {
               RaisePropertyChanged(); 
           }
       }
    }

    public bool Enabled 
    {
        get { return _enabled; }
        set
        {
           if (_enabled != value)
           {
               _enabled = value;

               IsDirty = true;
           }

           //Whatever code you need to raise the INotifyPropertyChanged.PropertyChanged event
           RaisePropertyChanged();
        }
    }
}

You're getting a binding error because you can't bind a control event directly to a method call.

Edit: Added a more complete example.

The example uses the MVVM Lite framework, but the approach should work with any MVVM implementation.

Upvotes: 0

plast1k
plast1k

Reputation: 843

Checked and Unchecked are events, so you can not bind to them like you can IsChecked, which is a property. On a higher level it is also probably wise for your view model not to know about a checkbox on the view.

I would create an event on the view model that fires when Enabled is changed, and you can subscribe to that and handle it any way you like.

private bool _enabled;

public bool Enabled
{
    get
    {
        return _enabled;
    }
    set
    {
        if (_enabled != value)
        {
            _enabled = value;
            RaisePropertyChanged("Enabled");
            if (EnabledChanged != null)
            {
                EnabledChanged(this, EventArgs.Empty);
            }
        }
    }
}

public event EventHandler EnabledChanged;
// constructor
public ViewModel()
{
    this.EnabledChanged += This_EnabledChanged;
}

private This_EnabledChanged(object sender, EventArgs e)
{
    // do stuff here
}

Upvotes: 1

Related Questions