0

我试图将视图模型中的枚举属性表示为视图中的一组单选按钮。到目前为止,一切都很好; 我可以用两种方式表达MultiBinding

(rb1.IsChecked, rb2.IsChecked, rb3.IsChecked) <-> vm.Value

这里使用的多重绑定将具有一个多重转换器,可以在(bool, bool, bool) <-> MyValue;之间进行转换。显然,类型的(三个)允许值之一是根据isMyValue来选择的,反之亦然。booltrue

不过,这已经有点不方便了:我无法在视图的 Xaml 中定义该绑定,因为必须从单个值的一侧定义多重绑定。因此,我必须在代码隐藏中定义多重绑定,并SetBinding在我的视图模型的Value属性上使用它。

现在,我遇到的问题是我不只是将一组单选按钮绑定到该值,而是两个。因此,我的绑定必须如下所示:

(rbA1.IsChecked, rbA2.IsChecked, rbA3.IsChecked) <-> vm.Value <-> (rbB1.IsChecked, rbB2.IsChecked, rbB3.IsChecked)

问题是我不能使用一次SetBinding连接多个绑定vm.Value

到目前为止我尝试过的解决方案是:

  • 使用一个的多重绑定,一次绑定到所有单选按钮。这将意味着表单的绑定(rbA1.IsChecked, rbA2.IsChecked, rbA3.IsChecked, rbB1.IsChecked, rbB2.IsChecked, rbB3.IsChecked) <-> vm.Value。该解决方案的问题在于,如果选中了一个单选按钮(例如rbB2),我无法判断rbA2(未选中)或rbB2(选中)是否具有“新的、正确的”值。
  • 首先通过定义一个仅公开一个属性的单选组控件来抽象单选按钮组。SelectedIndex然后可以方便地从我的无线电组控件vm.Value的所有实例将此属性绑定到我的属性。虽然可行,但它需要编写一个新的控件类,我想知道这是否是 WPF 中的唯一方法。
  • 将一组单选按钮绑定到另一组:通过双向绑定rbB1to rbA1rbB2torbA2等,并且vm.Value仅在 my 和第一组单选按钮之间使用多重绑定,我会达到预期的效果,但我不喜欢拥有“主广播组”的概念。它将滥用 GUI 元素进行数据传输。
  • 在代码隐藏中执行所有操作并手动更新单选按钮和视图模型值。当然这是一个可行的后备解决方案,但这感觉在 Xaml/with 绑定中应该是可行的。
4

2 回答 2

0

将 VMEnum 单独绑定到每个 RadioButton(使用单个双向绑定)。每个绑定都应该有 CommandParameter 它是枚举。喜欢:

<RadioButton IsChecked="{Binding VMEnum, Converter={StaticResource EnumConverter}, ConverterParameter={Enums:VMEnums.FirstRadioButtonGroupA}}" />

在转换器中,

  • Convert 应该根据 VMEnum 和 COMmandParameter 返回正确的值(真/假)。本质上,逻辑是 VMEnum == (YourEnum)CommandParameter。
  • ConvertBack 应该根据 IsChecked 返回正确的枚举。如果 IsChecked 为真,则返回正确的枚举。否则返回 Binding.DoNothing ,这将中止该特定情况的绑定。
于 2012-09-22T18:34:39.983 回答
0

将复杂的多重绑定与转换器和代码隐藏一起使用不仅会使您的代码更难调试,而且更难测试。在我看来,最好将每组单选按钮(标志)表示为视图模型。在选中/取消选中任何单选按钮时评估您的值。

单选按钮组

public class RadioButtonGroup : ViewModel {

    public RadioButtonGroup(string groupName, int count, Action<bool[]> whenAnyChanaged = null) {

        RadioButtons = Enumerable.Range(0, count).Select(_ => {
            var button = new RadioButton { GroupName = groupName };
            button.PropertyChanged += (s, e) => {
                if (e.PropertyName == "IsChecked")
                    whenAnyChanaged(Flags);
            };
            return button;
        }).ToList();           
    }

    public List<RadioButton> RadioButtons { get; private set; }

    public bool[] Flags { get { return RadioButtons.Select(rb => rb.IsChecked).ToArray(); } }
}

单选按钮

 public class RadioButton : ViewModel {

    private bool isChecked;

    public bool IsChecked {
        get { return isChecked; }
        set { SetProperty(ref this.isChecked, value); }
    }

    public string GroupName { get; set; }
}

主视图模型

public class MainViewModel : ViewModel {
    public MainViewModel() {
        GroupA = new RadioButtonGroup("A", 10, flags => GroupToggle(flags, GroupB.Flags));
        GroupB = new RadioButtonGroup("B", 10, flags => GroupToggle(GroupA.Flags, flags));
    }

    public RadioButtonGroup GroupA { get; private set; }

    public RadioButtonGroup GroupB { get; private set; }

    void GroupToggle(bool[] groupA, bool[] groupB) {
        MyValue = Evaluate(groupA, groupB);
    }
}

看法

<Window x:Class="WpfLab.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="{Binding Title}" Height="350" Width="525">
<Window.Resources>
    <DataTemplate x:Key="RadioButton">
        <RadioButton IsChecked="{Binding IsChecked, Mode=OneWayToSource}" GroupName="{Binding GroupName}"/>
    </DataTemplate>
</Window.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="30"/>
    </Grid.RowDefinitions>

    <ListBox Grid.Row="0" ItemsSource="{Binding GroupA.RadioButtons}" ItemTemplate="{StaticResource ResourceKey=RadioButton}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>

    <ListBox Grid.Row="1" ItemsSource="{Binding GroupB.RadioButtons}" ItemTemplate="{StaticResource ResourceKey=RadioButton}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Grid>

于 2012-09-22T10:42:17.750 回答