ItemsControl 上的 WPF MVVM 单选按钮
我之前已经将枚举绑定到单选按钮,并且我通常了解它是如何工作的。我使用了这个问题的替代实现:如何绑定RadioButtons 到枚举?
我想生成自定义类型的运行时枚举集,并将其呈现为一组单选按钮,而不是枚举。我已经获得了一个针对带有 ListView
的运行时枚举集的视图,绑定到 ItemsSource
和 SelectedItem
属性,所以我的 ViewModel
已正确连接。现在我尝试从 ListView
切换到带有单选按钮的 ItemsControl
。
据我所知:
<Window.Resources>
<vm:InstanceToBooleanConverter x:Key="InstanceToBooleanConverter" />
</Window.Resources>
<!-- ... -->
<ItemsControl ItemsSource="{Binding ItemSelections}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type vm:ISomeType}">
<RadioButton Content="{Binding Name}"
IsChecked="{Binding Path=SelectedItem, Converter={StaticResource InstanceToBooleanConverter}, ConverterParameter={Binding}}"
Grid.Column="0" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
InstanceToBooleanConverter
与其他问题中的 EnumToBooleanConverter
具有相同的实现。这似乎是正确的,因为它似乎只是调用了 Equals
方法:
public class InstanceToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(true) ? parameter : Binding.DoNothing;
}
}
我现在遇到的问题是我无法弄清楚如何将运行时值作为 ConverterParameter
发送代码>.当我尝试(使用上面的代码)时,出现此错误:
无法在“Binding”类型的“ConverterParameter”属性上设置“Binding”。 “绑定”只能在 DependencyObject 的 DependencyProperty 上设置。
有没有办法绑定到项目实例,并将其传递给IValueConverter
?
I've bound enums to radio buttons before, and I generally understand how it works. I used the alternate implementation from this question: How to bind RadioButtons to an enum?
Instead of enumerations, I'd like to generate a runtime-enumerated set of a custom type and present those as a set of radio buttons. I have gotten a view working against a runtime-enumerated set with a ListView
, binding to the ItemsSource
and SelectedItem
properties, so my ViewModel
is hooked up correctly. Now I am trying to switch from a ListView
to a ItemsControl
with radio buttons.
Here's as far as I've gotten:
<Window.Resources>
<vm:InstanceToBooleanConverter x:Key="InstanceToBooleanConverter" />
</Window.Resources>
<!-- ... -->
<ItemsControl ItemsSource="{Binding ItemSelections}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type vm:ISomeType}">
<RadioButton Content="{Binding Name}"
IsChecked="{Binding Path=SelectedItem, Converter={StaticResource InstanceToBooleanConverter}, ConverterParameter={Binding}}"
Grid.Column="0" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
InstanceToBooleanConverter
has the same implementation as EnumToBooleanConverter
from that other question. This seems right, since it seems like it just invokes the Equals
method:
public class InstanceToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(true) ? parameter : Binding.DoNothing;
}
}
The problem I am getting now is that I can't figure out how to send a runtime value as the ConverterParameter
. When I try (with the code above), I get this error:
A 'Binding' cannot be set on the 'ConverterParameter' property of type 'Binding'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
Is there a way to bind to the item instance, and pass it to the IValueConverter
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
事实证明,放弃使用
ItemsControl
而使用ListBox
要简单得多。它可能更重,但这主要是因为它正在为您做繁重的工作。在
RadioButton.IsChecked
和ListBoxItem.IsSelected
之间进行双向绑定非常容易。使用ListBoxItem
的正确控件模板,您可以轻松摆脱所有选择视觉效果。It turns out that it is much simpler to abandon using
ItemsControl
and instead go withListBox
.It may be more heavy-weight, but that's mostly because it is doing the heavy lifting for you. It is really easy to do a two-way binding between
RadioButton.IsChecked
andListBoxItem.IsSelected
. With the proper control template for theListBoxItem
, you can easily get rid of all the selection visual.据我所知,没有什么好的方法可以使用 MultiBinding 来做到这一点,尽管您最初认为会有。由于您无法绑定
ConverterParameter
,因此您的ConvertBack
实现没有所需的信息。我所做的是创建一个单独的
EnumModel
类,仅用于将枚举绑定到单选按钮。在ItemsSource
属性上使用转换器,然后绑定到EnumModel
。EnumModel
只是一个使绑定成为可能的转发器对象。它保存枚举的一个可能值和对视图模型的引用,以便它可以将视图模型上的属性与布尔值相互转换。这是一个未经测试但通用的版本:
转换器:
EnumModel:
对于我知道有效的代码示例(但它仍然很未经修饰 - WIP!),您可以看到 http://code.google.com/p/pdx/source/browse/trunk/PDX/ PDX/Toolkit/EnumControl.xaml.cs。这仅在我的库的上下文中有效,但它演示了基于
DescriptionAttribute
设置 EnumModel 的名称,这可能对您有用。As far as I know, there's no good way to do this with a
MultiBinding
, although you initially think there would be. Since you can't bind theConverterParameter
, yourConvertBack
implementation doesn't have the information it needs.What I have done is created a separate
EnumModel
class solely for the purpose of binding an enum to radio buttons. Use a converter on theItemsSource
property and then you're binding to anEnumModel
. TheEnumModel
is just a forwarder object to make binding possible. It holds one possible value of the enum and a reference to the viewmodel so it can translate a property on the viewmodel to and from a boolean.Here's an untested but generic version:
The converter:
The EnumModel:
For a code sample that I know works (but it's still quite unpolished - WIP!), you can see http://code.google.com/p/pdx/source/browse/trunk/PDX/PDX/Toolkit/EnumControl.xaml.cs. This only works within the context of my library, but it demonstrates setting the Name of the EnumModel based on the
DescriptionAttribute
, which might be useful to you.现在我知道了 x:Shared (感谢您的其他问题 ),我放弃之前的答案,并说 MultiBinding 才是正确的选择。
XAML:
视图模型:
转换器:
Now that I know about x:Shared (thanks to your other question), I renounce my previous answer and say that a
MultiBinding
is the way to go after all.The XAML:
The viewmodel:
The converter:
你是如此接近。当一个转换器需要两个绑定时,您需要一个
MultiBinding
和一个IMultiValueConverter
!语法有点冗长,但并不困难。编辑:
这里有一些代码让你开始吧。
绑定:
和转换器:
第二次编辑:
上述方法对于使用问题中链接的技术实现双向绑定没有用,因为转换回来时无法获得必要的信息。
我认为正确的解决方案是直接的 MVVM:对视图模型进行编码以匹配视图的需求。代码量非常小,并且不需要任何转换器或有趣的绑定或技巧。
这是 XAML;
和代码隐藏来模拟视图模型:
以及一些视图模型基础设施:
You are so close. When you are need two bindings for one converter you need a
MultiBinding
and aIMultiValueConverter
! The syntax is a little more verbose but no more difficult.Edit:
Here's a little code to get you started.
The binding:
and the converter:
Second Edit:
The above approach is not useful to implement two-way binding using the technique linked in the question because the necessary information is not available when converting back.
The correct solution I believe is straight-up MVVM: code the view-model to match the needs of the view. The amount of code is quite small and obviates the need for any converters or funny bindings or tricks.
Here is the XAML;
and code-behind to simulate the view-model:
and some view-model infrastructure: