【问题标题】:Databind radiobutton group to property将单选按钮组数据绑定到属性
【发布时间】:2010-11-27 23:44:11
【问题描述】:

我有一个单选按钮组:

<TextBlock Height="24" Text="Update Interval (min):"/>
<RadioButton x:Name="radioButtonTimerNone" IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, Mode=TwoWay}"} Content="None" />
<RadioButton x:Name="radioButtonTimerOne" IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, Mode=TwoWay}" 
                Content="1" />
<RadioButton x:Name="radioButtonTimerFive" IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, Mode=TwoWay}" 
                Content="5" />

还有一个属性:

    public int UpdateInterval {
        get { return _updateInterval; }
        set { _updateInterval = value;
            onPropertyChanged("UpdateInterval");
        }
    }

如何将单选按钮绑定到属性,所以当 UpdateInterval 为 0 时检查 radioButtonTimerNone,当 UpdateInterval 为 1 时检查 radioButtonTimerOne,等等。
我试图创建一个转换器,但它无法识别正在设置的 rb:

[ValueConversion(typeof(RadioButton), typeof(bool))] 
class UpdateIntervalToCheckedConverter : System.Windows.Data.IValueConverter
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

我希望 'value' 是一个单选按钮,但它似乎是 UpdateInterval 的值。

感谢您的任何提示...

【问题讨论】:

    标签: wpf data-binding xaml


    【解决方案1】:

    您的值转换器不会被告知哪个 RadioButton 更改了值 - 绑定只知道“IsChecked”属性已更改,因此 IsChecked 的新值是它可以告诉转换器的唯一信息。

    我首先想到的是为每个绑定提供一个转换器参数:

    <RadioButton 
        x:Name="radioButtonTimerNone" 
        IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, ConverterParameter=0, Mode=TwoWay}"
        Content="None" />
    <RadioButton
        x:Name="radioButtonTimerOne"
        IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, ConverterParameter=1, Mode=TwoWay}"
        Content="1" />
    <RadioButton 
        x:Name="radioButtonTimerFive"
        IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, ConverterParameter=5, Mode=TwoWay}"
        Content="5" />
    

    因此,现在“Convert”方法的“parameter”参数将具有值“0”、“1”或“5”,具体取决于选中的 RadioButton。我认为,虽然我不确定,该参数将是字符串类型,因此在查询值时可能必须考虑到这一点。

    【讨论】:

    • 谢谢,我已经根据您的建议让它工作了。但是,看起来不是很干净,必须传递本质上是我想要绑定到属性的控件的 ID....
    • 是的,我不知道是否有“更清洁”的解决方案。一般来说,我不是价值转换器的忠实拥护者,但如果你必须使用一个,那么 ConverterParameter 可以让你的生活更轻松!
    • 这是我选择的解决方案。虽然它不是很干净,但我通常比安德森在 ViewModel 上拥有一堆属性的解决方案更喜欢它。但是,我想,那是因为我真的不喜欢让我的 ViewModel 迎合视图,所以我可以支持结构化皮肤。
    • 呃... ViewModel 应该迎合视图... 它甚至在名称中 :) 这不是我最初的观点... 我从 WPF 门徒那里偷来的:@987654321 @
    • 是否可以将radiobutton对象作为参数传递?
    【解决方案2】:

    如果您使用 MVVM 并绑定到 ViewModel(我猜您是这样),我通常认为我的 ViewModel 是一个大的 ValueConverter。为什么不将该逻辑放入每个属性中?

    这是其中之一的示例:

    public bool Timer5Enabled
    {
         get { return UpdateInterval == 5; }
    }
    

    然后你就绑定到那个:

    <RadioButton
        x:Name="radioButtonTimerOne"
        IsChecked="{Binding Timer5Enabled, Mode=OneWay}"
        Content="1" />
    

    您唯一需要更改的是绑定您的间隔更新逻辑来为您的依赖属性引发 OnChanged:

    public int UpdateInterval {
            get { return _updateInterval; }
            set { _updateInterval = value;
                onPropertyChanged("UpdateInterval");
                onPropertyChanged("Timer5Enabled");
                onPropertyChanged("...");
            }
        }
    

    如果可以,最好避免使用 ValueConverters。

    【讨论】:

      【解决方案3】:

      您可能会考虑使用不同间隔的List&lt;...&gt;。列表类型最好是一些自定义类型(例如 UpdateInterval)或 KeyValuePair&lt;K,V&gt;,以便将向用户显示的内容与实际值分离。

      然后您可以将ListBox 绑定到此列表,并将每个ListBoxItem 模板化为显示RadioButton。然后,在模板中,将单选按钮的IsChecked 绑定到ListBoxItem.IsSelected

      最后一步就是将您的属性绑定到ListBoxSelectedItemSelectedValue

      【讨论】:

        【解决方案4】:

        这对我来说是一个非常烦人的问题。

        当您将多个 RadioButtons 分配给同一个 GroupName 时,WPF RadioButton 类存在一个错误,该错误会删除 IsChecked 属性的绑定。人们已经提供了很多解决方法,但是当我不得不再次访问这个时,我想出了一个不会让我反胃的方法。

        所以你要做的就是用这个继承 RadioButton 类:

        public class RadioButton: System.Windows.Controls.RadioButton
        {
            protected override void OnClick()
            {
                base.OnClick();
        
                SetValue(CurrentValueProperty,CheckedValue);
            }
        
            public int CurrentValue
            {
                get { return (int)GetValue(CurrentValueProperty); }
                set { SetValue(CurrentValueProperty, value); }
            }
        
            // Using a DependencyProperty as the backing store for CurrentValue.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty CurrentValueProperty =
                DependencyProperty.Register("CurrentValue", typeof(int), typeof(RadioButton), new FrameworkPropertyMetadata(0,FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, CurrentValue_Changed));
        
            public static void CurrentValue_Changed(object sender, DependencyPropertyChangedEventArgs e)
            {
                 ((RadioButton)sender).IsChecked = ((RadioButton)sender).CurrentValue == ((RadioButton)sender).CheckedValue;
            }
        
            public int CheckedValue
            {
                get { return (int)GetValue(CheckedValueProperty); }
                set { SetValue(CheckedValueProperty, value); }
            }
        
            // Using a DependencyProperty as the backing store for CheckedValue.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty CheckedValueProperty =
                DependencyProperty.Register("CheckedValue", typeof(int), typeof(RadioButton), new UIPropertyMetadata(0));
        }
        

        所有这一切都是添加两个依赖属性,以便您可以进行相等比较。

        因此,在 XAML 中,示例如下:

          <UserControl x:Class="MyClass"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:c="clr-namespace:MVVMLibrary;assembly=MVVMLibrary"
            Height="Auto" Width="Auto">
        
                    <c:RadioButton CurrentValue="{Binding MyValue}" CheckedValue="1"  GroupName="SearchType" >Value 1</c:RadioButton>
                    <c:RadioButton Grid.Column="1" CurrentValue="{Binding MyValue}" CheckedValue="2" GroupName="SearchType" >Value 2</c:RadioButton>
          </UserControl>
        

        所以如果你注意到你所做的就是 1) 绑定到 CurrentValue 属性 2) 将 CheckedValue 属性设置为使 RadioButton 被选中的值 3) 将 RadioButtons 设置为相同的 GroupName

        如果您注意到我创建了 CurrentValue 和 CheckedValue int 类型。我这样做的原因是您实际上可以将 CurrentValue 绑定到枚举。我认为这很棒,但这只是我的意见,可能并不重要。 :)

        希望这对某人有所帮助。

        【讨论】:

          【解决方案5】:

          一种可能性是实现一个 IValueConverter 并对其进行配置,并为您需要绑定的每个 RadioButton 传递预期的枚举值,正如我在我的博客中描述的 here

          【讨论】:

            猜你喜欢
            • 2012-03-02
            • 2014-10-14
            • 2014-02-03
            • 2017-06-22
            • 1970-01-01
            • 2014-06-06
            • 1970-01-01
            • 1970-01-01
            • 2021-05-24
            相关资源
            最近更新 更多