0

I have a radio button group in a listview. The rows of this listview (which contain the radio button grp amongst other things) is an observable collection.

the code I have written goes something like this:

The Xaml:

    <RadioButton Content="EnumValueName1"
             GroupName="RadButGrp1"
             IsChecked="{Binding propertyName,Mode=TwoWay,Converter={StaticResource EnumToBoolConverter},ConverterParameter=EnumValueName1}" >
 </RadioButton>
 <RadioButton Content="EnumValueName2" 
              GroupName="RadButGrp1"
              IsChecked="{Binding propertyName,Mode=TwoWay,Converter={StaticResource EnumToBoolConverter},ConverterParameter=EnumValueName2}">
 </RadioButton>
<RadioButton Content="EnumValueName3" 
              GroupName="RadButGrp1"
              IsChecked="{Binding propertyName,Mode=TwoWay,Converter={StaticResource EnumToBoolConverter},ConverterParameter=EnumValueName3}">
 </RadioButton>

I am trying to bind directly to the data field called propertyName in my data structure defining the table that holds these values. I do NOT have this field in my ViewModel class for this view. I did this to avoid keeping track of the index of the collection that I am currently populating. (or so i'd like to think!)

The converter:

 public class EnumBooleanConverter : IValueConverter
 {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;

        if (value == null || Enum.IsDefined(value.GetType(), value) == false)
            return DependencyProperty.UnsetValue;

        object parameterValue = Enum.Parse(value.GetType(), parameterString);

        return parameterValue.Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null || value.Equals(false))
            return DependencyProperty.UnsetValue;

        return Enum.Parse(targetType, parameterString);
    }
 }

The problem is that in the ConvertBack function at the Enum.Parse line, the following Argument exception occurs:

Type provided must be an Enum. Parameter name: enumType

Is there a way to return an enum type to the binding? How do I tell the radio buttons which enumeration value it represents? How do I write a function that returns the appropriate enum value to the binding?

Hoping you guys can help. Thanks in advance!

pyridot
  • 5
  • 1
  • 7
  • 1
    Have you seen this: http://stackoverflow.com/questions/397556/how-to-bind-radiobuttons-to-an-enum – Phil Mar 12 '13 at 14:12
  • Only a comment as I don't follow the full question. What I do is pack the enum as the key and value as the value into a Dictionary. – paparazzo Mar 12 '13 at 14:18
  • I tried the solution from the link u gave but I still get the same error. – pyridot Mar 12 '13 at 14:35

3 Answers3

0

Try this, it's my version of the EnumToBoolConverter:

public class EnumToBoolConverter : BaseConverterMarkupExtension<object, bool>
{
    public override bool Convert(object value, Type targetType, object parameter)
    {
        if (value == null)
            return false;

        return value.Equals(Enum.Parse(value.GetType(), (string)parameter, true));
    }

    public override object ConvertBack(bool value, Type targetType, object parameter)
    {
        return value.Equals(false) ? DependencyProperty.UnsetValue : parameter;
    }
}
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • Now I get a Red box around the checked radio button. Also the targetType is still not enum. Can I write something in the viewmodel that will actually return an enum? Beginning to get really confused here! :( – pyridot Mar 12 '13 at 15:16
  • That only works if you bind to an `Enum` source property. I don't know what you're binding to. – Federico Berasategui Mar 12 '13 at 15:26
  • ok maybe my question is how does one bind a radio button group who's values are a part of an observable collection? – pyridot Mar 13 '13 at 04:23
  • the field i'm binding to in the data structure is an int? .....is that was what you were asking :S – pyridot Mar 13 '13 at 04:23
0

Ok the solution was relatively simple once I got the concept right. I have done the following which partially solves my problem.

 <RadioButton Content="EnumValueName1" 
              GroupName="RadBtnGrp1"
              IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ParentControl}},
                                  Path=DataContext.propName,
                                  Mode=TwoWay,
                                  Converter={StaticResource EnumToBoolConverter},ConverterParameter=EnumValueName1}">

 </RadioButton>

The targetType in my ConvertBack function now the correct enum type. Hope this helps!

Now i have to figure out how to make the radiobuttons retain selections in multiple rows of the listview. Presently they a selection in first row deselects the same group from the rest of the rows.

Thank you for your help so far. If anyone can point me to a solution for the new problem that would be really great!

pyridot
  • 5
  • 1
  • 7
  • generating unique group names for each group of radio buttons on each new row of list view will solve the deselection problem :) Should have known that! :( – pyridot Mar 13 '13 at 13:11
0

Recommend you to create the radio buttons dynamically, ListBox can help us do that, without converters. The advantage of this method is below: if someday your enum class changes, you do not need to update the GUI (XAML file).

The steps of this method are below:
create a ListBox and set the ItemsSource for the listbox as the enum and binding the SelectedItem of the ListBox to the selected property. Then the Radio Buttons for each ListBoxItem will be created.

  • Step 1: Re-define your Enum.
public enum EnumValueNames
{ 
   EnumValueName1, 
   EnumValueName2, 
   EnumValueName3
}

Then add below property to your DataContext (or ViewModel of MVVM), which records the selected item which is checked.

public EnumValueNames SelectedEnumValueName { get; set; }
  • Step 2: add the enum to static resources for your Window, UserControl or Grid etc.
    <Window.Resources>
        <ObjectDataProvider MethodName="GetValues"
                            ObjectType="{x:Type system:Enum}"
                            x:Key="EnumValueNames">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:EnumValueNames" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
  • Step 3: Use the List Box and Control Template to populate each item inside as Radio button
    <ListBox ItemsSource="{Binding Source={StaticResource EnumValueNames}}" SelectedItem="{Binding SelectedEnumValueName, Mode=TwoWay}" >
        <ListBox.Resources>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <RadioButton
                                Content="{TemplateBinding ContentPresenter.Content}"
                                IsChecked="{Binding Path=IsSelected,
                                RelativeSource={RelativeSource TemplatedParent},
                                Mode=TwoWay}" />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.Resources>
    </ListBox>

References: https://www.codeproject.com/Articles/130137/Binding-TextBlock-ListBox-RadioButtons-to-Enums

Bravo Yeung
  • 8,654
  • 5
  • 38
  • 45