سؤال

I have like 10 buttons on the view, which, when clicked should set adequate property on ViewModel to null (ViewModel is DataContext for View). Think of it like a reset action.

Currently what i have is an ICommand in ViewModel, that each button"s Command is bound to, and then I set a CommandParameter to some value, which will allow me to distinguish what property on ViewModel needs to be updated.

In order to avoid bunch of Ifs, I am thinking of doing something like this (incorrect syntax):

<Button ...>
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
      <Setter Property="PropertyA" Source="DataContext-ViewModel" Value="x:null" />
    </i:EventTrigger>
  <i:Interaction.Triggers>
</Button>

Is this possible to achieve, and how?

هل كانت مفيدة؟

المحلول

If using Reflection an option for you, then you could use Reflection to set properties in the ViewModel.

Your command execute method will become something like this:

this.GetType().GetProperty((string)CommandParameter).SetValue(this, null, new object[] {});

However, if you prefer the XAML route you mentioned in your question, then you could create a TriggerAction and use that in the EventTrigger. Below is what I tried:

public sealed class SetProperty : TriggerAction<FrameworkElement>
{
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof (object), typeof (SetProperty), new PropertyMetadata(default(object)));

    /// <summary>
    /// Source is DataContext
    /// </summary>
    public object Source
    {
        get { return (object) GetValue(SourceProperty); }
        set { SetValue(SourceProperty, value); }
    }

    public static readonly DependencyProperty PropertyNameProperty =
        DependencyProperty.Register("PropertyName", typeof (string), typeof (SetProperty), new PropertyMetadata(default(string)));

    /// <summary>
    /// Name of the Property
    /// </summary>
    public string PropertyName
    {
        get { return (string) GetValue(PropertyNameProperty); }
        set { SetValue(PropertyNameProperty, value); }
    }

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof (object), typeof (SetProperty), new PropertyMetadata(default(object)));

    /// <summary>
    /// Value to Set
    /// </summary>
    public object Value
    {
        get { return (object) GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    protected override void Invoke(object parameter)
    {
        if (Source == null) return;
        if (string.IsNullOrEmpty(PropertyName)) return;

        Source.GetType().GetProperty(PropertyName).SetValue(Source, Value, new object[] {});
    }
}

and XAML:

<Button Content="Reset">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <local:SetProperty Source="{Binding}" PropertyName="PropertyToSet" Value="{x:Null}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

If you do not like Reflection at all, then you could have a Dictionary of Actions in your Viewmodel:

_propertyResetters = new Dictionary<string, Action>
{
    {"PropertyToSet", () => PropertyToSet = null}
};

And, in your Command Execute method you can invoke these actions by doing _propertyResetters[(string)CommandParameter]();

Hope this helps or gives you some ideas.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top