如何从viewmodel更新视图中的单选按钮?

时间:2015-12-24 22:55:32

标签: c# wpf mvvm data-binding prism

假设我在view.xaml中有几个单选按钮组合在一起:

<RadioButton GroupName="Group" Content="Item1" Command="{Binding ChangeRadioSelectionCommand}" CommandParameter="Item1" />
<RadioButton GroupName="Group" Content="Item2" Command="{Binding ChangeRadioSelectionCommand}" CommandParameter="Item2" />
<RadioButton GroupName="Group" Content="Item3" Command="{Binding ChangeRadioSelectionCommand}" CommandParameter="Item3" />

然后在我的viewmodel.cs我有类似的东西:

public class ViewModel : BindableBase
{
  private string radioSelection = "Item1";
  public string RadioSelection
  {
    get { return this.radioSelection; }
    set { SetProperty(ref this.radioSelection, value); }
  }

  public ViewModel() 
  {
    this.ChangeRadioSelectionCommand = new DelegateCommand<string>(this.OnChangeRadioSelection, this.CanChangeRadioSelection);
  }

  public ICommand ChangeRadioSelectionCommand { get; private set; }
  private void OnChangeRadioSelection(string radioSelection)
  {
    RadioSelection = radioSelection;
  }
  private bool CanChangeRadioSelection(string radioSelection) { return true; }
}

这适用于从视图中获取视图模型的值,但是如果viewmodel中的某些内容发生了变化,我将如何从视图模型转到视图。为简单起见,我们假设我在xaml上添加了一个按钮:

<Button Command="{Binding ResetRadioSelectionCommand}" />

它所做的只是将无线电选择重置为第一项,因此viewmodel.cs看起来像:

public class ViewModel : BindableBase
{
  private string radioSelection = "Item1";
  public string RadioSelection
  {
    get { return this.radioSelection; }
    set { SetProperty(ref this.radioSelection, value); }
  }

  public ViewModel() 
  {
    this.ChangeRadioSelectionCommand = new DelegateCommand<string>(this.OnChangeRadioSelection, this.CanChangeRadioSelection);
    this.ResetRadioSelectionCommand = new DelegateCommand(this.OnResetRadioSelection, this.CanResetRadioSelection);
  }

  public ICommand ChangeRadioSelectionCommand { get; private set; }
  private void OnChangeRadioSelection(string radioSelection)
  {
    RadioSelection = radioSelection;
  }
  private bool CanChangeRadioSelection(string radioSelection) { return true; }

  public ICommand ResetRadioSelectionCommand { get; private set; }
  private void OnResetRadioSelection()
  {
    RadioSelection = "Item1";
  }
  private bool CanResetRadioSelection() { return true; }
}

这会改变radioSelection,但它不会反映在gui中。有没有办法做到这一点?或者也许只是处理单选按钮的更好方法?

1 个答案:

答案 0 :(得分:3)

这完全是错误的方式。您的ViewModel应包含具有合理名称的合理属性。例如,CurrentMode。

第一个解决方案

视图模型

public enum DisplayMode { Vertical, Horizontal, Diagonal }

private DisplayMode currentMode;
public DisplayMode CurrentMode
{
    get { return currentMode; }
    set { SetProperty(ref currentMode, value); }
}

现在您可以通过RadioButton.IsChecked将此属性绑定到IValueConverter

<RadioButton GroupName="Group" Content="Vertical" IsChecked="{Binding CurrentMode, Converter={StaticResource enumToBoolConverter}, ConverterParameter=Vertical}" />
<RadioButton GroupName="Group" Content="Horizontal" IsChecked="{Binding CurrentMode, Converter={StaticResource enumToBoolConverter}, ConverterParameter=Horizontal}" />
<RadioButton GroupName="Group" Content="Diagonal" IsChecked="{Binding CurrentMode, Converter={StaticResource enumToBoolConverter}, ConverterParameter=Diagonal}" />

Converter对所有枚举都是通用的。您需要将它添加到项目中并在视图的资源块中声明。

public class EnumBooleanConverter : IValueConverter
{
    #region IValueConverter Members
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;

        if (Enum.IsDefined(value.GetType(), value) == false)
            return DependencyProperty.UnsetValue;

        object parameterValue = Enum.Parse(value.GetType(), parameterString);

        return parameterValue.Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;

        return Enum.Parse(targetType, parameterString);
    }
    #endregion
}

这是众多解决方案之一。您可能不希望我们为您的属性枚举,因为主题区域未映射到参数的枚举。然后你可以绑定到文本值:

第二个解决方案

视图模型

private string currentMode;
public string CurrentMode
{
    get { return currentMode; }
    set { SetProperty(ref currentMode, value); }
}

查看

<RadioButton Name="RadioButton1"
                     GroupName="Group"
                     Content="Vertical"
                     IsChecked="{Binding Path=CurrentMode, Converter={StaticResource boolToStringValueConverter}, ConverterParameter=Vertical}" />
        <RadioButton Name="RadioButton2"
                     GroupName="Group"
                     Content="Horizontal"
                     IsChecked="{Binding Path=CurrentMode, Converter={StaticResource boolToStringValueConverter}, ConverterParameter=Horizontal}" />
        <RadioButton Name="RadioButton3"
                     GroupName="Group"
                     Content="Diagonal"
                     IsChecked="{Binding Path=CurrentMode, Converter={StaticResource boolToStringValueConverter}, ConverterParameter=Diagonal}" />

转换器

public class BooleanToStringValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (System.Convert.ToString(value).Equals(System.Convert.ToString(parameter)))
        {
            return true;
        }
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (System.Convert.ToBoolean(value))
        {
            return parameter;
        }
        return null;
    }
}

一般原则是在ViewModels中存储主题区域的有意义的投影。如果您将视图属性的商店副本保留在ViewModel中,则没有多少意义。 RadioSelection是一个毫无意义的名称,如果没有额外的评论,它就无法与模型相关联。