将RadioButtons重新绑定到枚举时不会发生绑定

时间:2010-07-14 23:12:48

标签: wpf binding enums radio-button

在查看将enum绑定到一组RadioButton的解决方案时,我发现Sampost来自一年半前。

Lars'答案正是我所寻找的:简单有效。

直到我开始更改绑定到RadioButton组的对象。一个简单的版本如下。

XAML:

<Window x:Class="RadioEnum.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:re="clr-namespace:RadioEnum"
        Height="200" Width="150">
  <Window.DataContext>
    <re:ViewModel />
  </Window.DataContext>
  <Window.Resources>
    <re:EnumBooleanConverter x:Key="enumBooleanConverter" />
  </Window.Resources>
    <DockPanel>
    <ComboBox DockPanel.Dock="Top" IsSynchronizedWithCurrentItem="True"
              ItemsSource="{Binding Things}" DisplayMemberPath="Name" />
    <GroupBox>
      <StackPanel>
        <RadioButton IsChecked="{Binding Path=Things/Choice, Converter={StaticResource enumBooleanConverter}, ConverterParameter=First}">First</RadioButton>
        <RadioButton IsChecked="{Binding Path=Things/Choice, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Second}">Second</RadioButton>
        <RadioButton IsChecked="{Binding Path=Things/Choice, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Third}">Third</RadioButton>
      </StackPanel>
    </GroupBox>
  </DockPanel>
</Window>

现在,C#:

namespace RadioEnum
{
    public class ViewModel {
        public ObservableCollection<Thing> Things { get; set; }

        public ViewModel() {
            Things = new ObservableCollection<Thing> {
                new Thing{ Name = "Thing1", Choice = Choice.First, },
                new Thing{ Name = "Thing2", Choice = Choice.Second, },
            };
        }
    }

    public class Thing {
        public string Name { get; set; }
        public Choice Choice { get; set; }
    }

    public enum Choice { None, First, Second, Third, }

    public class EnumBooleanConverter : IValueConverter {
        // Yes, there are slight differences here from Lars' code, but that
        // was to ease debugging. The original version has the same symptom.
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            object ret = DependencyProperty.UnsetValue;
            var parameterString = parameter as string;

            if (parameterString != null && Enum.IsDefined(value.GetType(), value)) {
                object parameterValue = Enum.Parse(value.GetType(), parameterString);
                ret = parameterValue.Equals(value);
            }

            return ret;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            object ret = DependencyProperty.UnsetValue;
            var parameterString = parameter as string;

            if (parameterString != null && !value.Equals(false))
                ret = Enum.Parse(targetType, parameterString);

            return ret;
        }
    }
}

当应用程序使用ComboBox中的 Thing1 加载时,会在广播组中选择正确的选择。从ComboBox中选择 Thing2 会正确更新选择。但是,从这一点开始,切换不再更新绑定到 Second RadioButton,因此不再调用Convert方法,parameter设置为“第二”。

换句话说,虽然 Thing2 的值没有改变,但是从那一点开始,所有RadioButton都被清除了。但是, Thing1 继续有效。

没有看到错误 - “输出”窗口中既没有异常也没有消息。我试过以不同的方式绑定。我也试过选择一个DependencyProperty(和Thing然后是DependencyObject)。

有任何见解吗?

2 个答案:

答案 0 :(得分:1)

原始回复: 不确定这是否能解决您的问题...因为我认为绑定的中断可能在您的组合框中...但是要改进您的EnumConverter并确保它正常工作......我建议看看在我对这个问题的回答中:

How to bind RadioButtons to an enum?

(不是选定的答案......但是我使用通用转换器的响应而不是转换字符串值)

修改: 我刚接过你的代码并试了一下,一切似乎都很棒! (使用visual studio 2010 .net 4)

你有一个物品清单(在你的组合框中),可以通过单选按钮设置当前选择的东西的选择。我可以修改每个Thing的选择,当我在Things之间切换时,它会正确地为我更新单选按钮!

如果我对所需的功能有误,请纠正我:

App Loads - ComboBox:Thing1 RadioButton:First
选择Thing2 - ComboBox:Thing2 RadioButton:Second 选择Thing1 - ComboBox:Thing1 RadioButton:First
选择第三个 - ComboBox:Thing1 RadioButton:第三个 选择Thing2 - ComboBox:Thing2 RadioButton:Second 选择First - ComboBox:Thing2 RadioButton:First
选择Thing1 - ComboBox:Thing1 RadioButton:Third
选择Thing2 - ComboBox:Thing2 RadioButton:First

以上是使用您提供的代码(以及修改后的EnumConverter)运行应用程序时获得的功能。这似乎也是理想的结果。以上是否正确,这对你不起作用吗?

编辑2:我可以确认问题出在.NET 3.5上

我运行.NET 4客户端配置文件...一切正常工作...运行.NET 3.5客户端配置文件...我得到你说的结果。

答案 1 :(得分:0)

对于那些可能在.NET 3.5中坚持这样做的人,我确实有一些工作。它不像上面的代码那么优雅,但它起作用。

我也很高兴看到其他人对替代方法的反馈。以下示例代码适用于在.NET 3.5和4中均可运行的 ThingB

首先,按如下方式更改RadioButtons上的XAML(请注意,每个组的名称必须不同):

<RadioButton GroupName="One" IsChecked="{Binding Path=Things/ChoiceOne}">First</RadioButton>
<RadioButton GroupName="Two" IsChecked="{Binding Path=Things/ChoiceTwo}">Second</RadioButton>
<RadioButton GroupName="Three" IsChecked="{Binding Path=Things/ChoiceThree}">Third</RadioButton>

其次, ThingB 代码:

public class ThingB : INotifyPropertyChanged {
    public string Name { get; set; }

    public Choice Choice {
        get {
            return choiceOne ? Choice.First
                   : choiceTwo ? Choice.Second
                   : choiceThree ? Choice.Third : Choice.None;
        }
        set {
            choiceOne = Choice.First.Equals(value);
            choiceTwo = Choice.Second.Equals(value);
            choiceThree = Choice.Third.Equals(value);
        }
    }

    private bool choiceOne;
    public bool ChoiceOne {
        get { return choiceOne; }
        set {
            if(value) {
                Choice = Choice.First;
                NotifyChoiceChanged();
            }
        }
    }

    private bool choiceTwo;
    public bool ChoiceTwo {
        get { return choiceTwo; }
        set {
            if (value) {
                Choice = Choice.Second;
                NotifyChoiceChanged();
            }
        }
    }

    private bool choiceThree;
    public bool ChoiceThree {
        get { return choiceThree; }
        set {
            if (value) {
                Choice = Choice.Third;
                NotifyChoiceChanged();
            }
        }
    }

    private void NotifyChoiceChanged() {
        OnPropertyChanged("ChoiceOne");
        OnPropertyChanged("ChoiceTwo");
        OnPropertyChanged("ChoiceThree");
    }

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