简单的 WPF 单选按钮绑定?
将一组 3 个单选按钮绑定到值为 1、2 或 3 的 int 类型属性的最简单方法是什么?
What is the simplest way to bind a group of 3 radiobuttons to a property of type int for values 1, 2, or 3?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
我想出了一个简单的解决方案。
我有一个 model.cs 类:
我有 Window1.xaml.cs 文件,其中 DataContext 设置为 model.cs。 xaml 包含单选按钮:
这是我的转换器:
当然,在 Window1 的资源中:
I came up with a simple solution.
I have a model.cs class with:
I have Window1.xaml.cs file with DataContext set to model.cs. The xaml contains the radiobuttons:
Here is my converter:
And of course, in Window1's resources:
我很惊讶没有人想出这种解决方案将其绑定到 bool 数组。它可能不是最干净的,但它可以非常容易地使用:
在 XAML 中:
注意:如果您不想默认检查一种方式,则不需要双向绑定。双向绑定是该解决方案的最大缺点。
优点:
I am very surprised nobody came up with this kind of solution to bind it against bool array. It might not be the cleanest, but it can be used very easily:
in XAML:
NOTE: you don't need two-way binding if you don't want to one checked by default. TwoWay binding is the biggest con of this solution.
Pros:
使用更简单的方法更新答案
请参阅在同一页面上发布的我的新答案,以获取完全不同且更简单的方法解决这个问题。这种新方法使用自定义的
IValueConverter
和Binding
子类,让您可以重新使用真正的RadioButton
而不是风格繁重的ListBox
,如此处所示。再次强调,除非您个人在使用
ListBox
子类时能获得其他好处,否则其他方法 是我现在推荐的。原始答案
实际上,使用这样的转换器会破坏双向绑定,而且正如我上面所说,您也不能将其与枚举一起使用。更好的方法是使用针对 ListBox 的简单样式,如下所示:
注意:与 DrWPF.com 在其示例中所述相反,请勿将 ContentPresenter 放入 RadioButton 内,否则如果您添加带有按钮或其他内容等内容的项目,您将无法设置焦点或与其交互。这项技术解决了这个问题。此外,您需要处理文本的灰色化以及删除标签上的边距,否则它将无法正确呈现。这种风格也可以满足您的需求。
您现在拥有单选按钮的外观和感觉,但您可以进行双向绑定,并且可以使用枚举。方法如下...
另外,由于我们显式地分离出了针对 ListBoxItem 的样式,而不是将其内联,再次如其他示例所示,您现在可以从中创建一个新样式来自定义每个项目的内容间距等基础。 (如果您只是尝试以 ListBoxItem 为目标,则这将不起作用,因为键控样式会覆盖通用控制目标。)
下面是在每个项目的上方和下方放置 6 边距的示例。 (请注意,由于上述原因,您必须如何通过 ItemContainerStyle 属性显式应用样式,而不是简单地针对 ListBox 资源部分中的 ListBoxItem。)
Updated Answer with a Simpler Approach
Please see my new answer posted on this same page for a completely different, and much simpler approach to solving this issue. That new approach uses custom
IValueConverter
andBinding
subclasses which let you go back to using a trueRadioButton
instead of a heavily-styledListBox
, as shown here.Again, unless there are other benefits you'd personally gain when using a
ListBox
subclass, the other approach is what I now recommend.Original Answer
Actually, using the converter like that breaks two-way binding, plus as I said above, you can't use that with enumerations either. The better way to do this is with a simple style against a ListBox, like this:
Note: Contrary to what DrWPF.com stated in their example, do not put the ContentPresenter inside the RadioButton or else if you add an item with content such as a button or something else, you will not be able to set focus or interact with it. This technique solves that. Also, you need to handle the graying of the text as well as removing of margins on labels or else it will not render correctly. This style handles both for you as well.
You now have the look and feel of radio buttons, but you can do two-way binding, and you can use an enumeration. Here's how...
Also, since we explicitly separated out the style that tragets the ListBoxItem rather than putting it inline, again as the other examples have shown, you can now create a new style off of it to customize things on a per-item basis such as spacing. (This will not work if you simply try to target ListBoxItem as the keyed style overrides generic control targets.)
Here's an example of putting a margin of 6 above and below each item. (Note how you have to explicitly apply the style via the ItemContainerStyle property and not simply targeting ListBoxItem in the ListBox's resource section for the reason stated above.)
我知道这已经太晚了,但我有一个替代解决方案,它更轻、更简单。从
System.Windows.Controls.RadioButton
派生一个类,并声明两个依赖属性RadioValue
和RadioBinding
。然后在类代码中,重写OnChecked
并将RadioBinding
属性值设置为RadioValue
属性值。另一方面,使用回调捕获对RadioBinding
属性的更改,如果新值等于RadioValue
属性的值,则设置其IsChecked
属性设置为true
。这是代码:
XAML 用法:
希望有人在这段时间之后发现它很有用:)
I know it's way way overdue, but I have an alternative solution, which is lighter and simpler. Derive a class from
System.Windows.Controls.RadioButton
and declare two dependency propertiesRadioValue
andRadioBinding
. Then in the class code, overrideOnChecked
and set theRadioBinding
property value to that of theRadioValue
property value. In the other direction, trap changes to theRadioBinding
property using a callback, and if the new value is equal to the value of theRadioValue
property, set itsIsChecked
property totrue
.Here's the code:
XAML usage:
Hope someone finds this useful after all this time :)
我想出了使用从转换器返回的
Binding.DoNothing
的解决方案,它不会破坏双向绑定。用法:
单选按钮绑定:
I've come up with solution using
Binding.DoNothing
returned from converter which doesn't break two-way binding.Usage:
Radio button bindings:
改进和现在推荐的答案(例如方法2.0)
虽然我在此页面上提供了接受的答案,如下所示评论者正确地指出,尽管它功能强大且相当灵活,但当您只想按原样使用简单的
RadioButton
控件时,它的复杂性远非理想。因此,我提出了一种更新的方法,如下所示,它使用自定义
IValueConverter
及其ConvertBack< 中的
Binding.DoNothing
的强大功能/code> 方法,一种与RadioButton
控件进行双向绑定的神奇酱汁,现在可以按预期工作。RadioButtonValueConverter
让我们看一下转换器本身:
神奇之处在于在
ConvertBack
函数中使用Binding.DoNothing
。由于使用RadioButton
控件,每个“组”只能有一个活动选项(即只有一个IsChecked
设置为true
),我们确保只有具有该值的特定RadioButton
才是其绑定更新源的唯一按钮。其他RadioButton
实例上的那些根本不执行任何操作。以下是如何使用它按照 OP 的要求绑定到
int
值(下面,“cv”是转换器代码所在的导入命名空间,传递给转换器的值是特定的RadioButton
代表)...使用自定义
Binding
子类进一步简化虽然上述方法有效,但有很多重复的代码,并且 90% 的时间,您都没有这样做不要对绑定或转换器做任何特殊的事情。因此,让我们尝试使用为您设置转换器的
RadioButtonBinding
来简化事情。这是代码...通过这个新的绑定,调用站点大大简化了(这里,“b”是绑定代码所在的导入命名空间)...
绑定到枚举值
上面的示例涉及基本标量(例如 1、2、3) 。但是,如果我们想要的值是如下所示的枚举怎么办?
语法是相同的,但在调用站点,我们需要更具体地说明要绑定的值,使其更加详细。 (例如,如果您尝试单独传递“yes”,它将被视为字符串,而不是枚举,因此它将无法通过相等性检查。)
这是转换器版本的调用站点(此处,“v”是枚举值所在的导入命名空间)...
虽然更简单,但这是绑定版本的调用站点,更好,但仍然很冗长...
枚举类型特定的变体
如果您知道您将绑定到特定的枚举类型在许多情况下,您可以通过将早期的
RadioButtonValueConverter
和RadioButtonBinding
子类化为特定于枚举的变体来简化上述过程。下面正是使用上面定义的
TestEnum
进行的操作,如下所示...这是调用站点...
如您所见,XAML 解析器会自动为您处理字符串到枚举的转换使您的代码更易于阅读。没有比这更简单的了! :)
旁注:在更详细的声明中显式指定枚举值的版本的一个好处是,您可以自动完成枚举的情况。您无法通过为您转换字符串的特定于枚举类型的版本来实现这一点。但是,如果您使用无效的字符串值,后者将无法编译,因此需要权衡简洁性与自动完成便利性。
Improved and Now-Recommended Answer (e.g. approach 2.0)
While I provided the accepted answer to the question here on this page, as the commenters correctly call out, even though it's powerful and quite flexible, it's complexity is far from ideal when you just want to use simple
RadioButton
controls as-is.As such, I've come up with a newer approach, shown below, that instead uses a custom
IValueConverter
and the power ofBinding.DoNothing
in it'sConvertBack
method, the magic sauce that makes two-way bindings toRadioButton
controls now work as one would expect.The RadioButtonValueConverter
Let's take a look at the converter itself:
The magic sauce is in the use of
Binding.DoNothing
in theConvertBack
function. Since withRadioButton
controls, there can only be one active option per 'group' (i.e. only one withIsChecked
set totrue
), we ensure only the specificRadioButton
with that value is the only one whose binding updates the source. Those on the otherRadioButton
instances simply do nothing.Here's how you use it to bind to an
int
value as the OP asked (below, 'cv' is the imported namespace where the converter code resides, and the value you pass to the converter is the value that particularRadioButton
represents)...Simplifying further with a custom
Binding
SubclassWhile the above works, that's a lot of repeated code and for 90% of the time, you aren't doing anything special with the binding or converter. As such, let's try to simplify things with a
RadioButtonBinding
that sets up the converter for you. Here's the code...With this new binding, the call site is greatly simplified (here, 'b' is the imported namespace where the binding code resides)...
Binding to Enum Values
The above example dealt with basic scalars (e.g. 1, 2, 3). However, what if the value we want to is an enumeration such as the following?
The syntax is the same, but at the call-site, we need to be more specific about the value we're binding to making it much more verbose. (For instance, if you try and pass 'yes' by itself, it will be treated as a string, not an enum, so it will fail the equality check.)
Here's the converter version's call-site (here, 'v' is the imported namespace where the enum values reside)...
And while simpler, here's the binding version's call-site, better, but still verbose...
Enum-Type-Specific Variants
If you know you will be binding to a particular enum type on many occasions, you can simplify the above by subclassing the earlier
RadioButtonValueConverter
andRadioButtonBinding
to be enum-specific variants.Below is doing exactly that with
TestEnum
defined above, like so...And here are the call sites...
As you can see, the XAML parser automatically handles the string-to-enum conversion for you making your code much easier to read. Can't get much simpler than that! :)
Sidenote: One nice thing about the versions where you explicitly specify the enum value in its more-verbose declaration is you get auto-completion for the enum's cases. You don't get that with the enum-type-specific versions that convert the string for you. However, the latter will fail to compile if you use an invalid string value so the tradeoff is brevity vs auto-complete convenience.
这个例子可能看起来有点长,但是它的意图应该很清楚。
它在 ViewModel 中使用 3 个布尔属性,分别为
FlagForValue1
、FlagForValue2
和FlagForValue3
。这 3 个属性中的每一个都由一个名为
_intValue
的私有字段支持。视图 (xaml) 的 3 个单选按钮均绑定到视图模型中相应的 Flag 属性。这意味着显示“Value 1”的单选按钮绑定到视图模型中的
FlagForValue1
bool 属性,其他两个属性也相应绑定。在视图模型中设置其中一个属性(例如
FlagForValue1
)时,引发其他两个属性(例如FlagForValue2
和)的属性更改事件也很重要。 FlagForValue3
),以便 UI(WPFINotifyPropertyChanged
基础结构)可以正确选择/取消选择每个单选按钮。xaml 看起来像这样:
This example might be seem a bit lengthy, but its intention should be quite clear.
It uses 3 Boolean properties in the ViewModel called,
FlagForValue1
,FlagForValue2
andFlagForValue3
.Each of these 3 properties is backed by a single private field called
_intValue
.The 3 Radio buttons of the view (xaml) are each bound to its corresponding Flag property in the view model. This means the radio button displaying "Value 1" is bound to the
FlagForValue1
bool property in the view model and the other two accordingly.When setting one of the properties in the view model (e.g.
FlagForValue1
), its important to also raise property changed events for the other two properties (e.g.FlagForValue2
, andFlagForValue3
) so the UI (WPFINotifyPropertyChanged
infrastructure) can selected / deselect each radio button correctly.The xaml looks like this:
有时可以在模型中这样解决:
假设您有 3 个布尔属性 OptionA、OptionB、OptionC。
XAML:
代码:
你明白了。
不是最干净的东西,但很简单。
Sometimes it is possible to solve it in the model like this:
Suppose you have 3 boolean properties OptionA, OptionB, OptionC.
XAML:
CODE:
You get the idea.
Not the cleanest thing, but easy.
Aviad Ps 的回答效果很好。但是,我必须更改相等性检查以比较 OnRadioBindingChanged 中的字符串,否则将枚举与字符串值进行比较,并且最初不会检查单选按钮。
Aviad P.s answer works very well. However I had to change the equality check to compare strings in OnRadioBindingChanged otherwise the enum was compared to the string value and no radio button was checked initially.
我根据 Aviad 的答案创建了一个附加属性,它不需要创建新的类
用法:
I created an attached property based on Aviad's Answer which doesn't require creating a new class
usage :