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
?
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:
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.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.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: