2

When creating a RadioButton in XAML you can bind the state to the value of an int, as shown in this answer

However if the RadioButton is added to the window in c# code, how can we add this kind of binding?

A button is created as

RadioButton myRadBtn = new RadioButton();
myRadBtn.GroupName = "Some Group";

and I have a converter class ready

public class RadBtnConverter : IValueConverter
{
    //Convert a number to radiobutton value by returning true if the radiobutton number (given as the parameter) is the same as the value passed in to convert
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var para = System.Convert.ToInt32(parameter);
        var myChoice = System.Convert.ToInt32(value);
        return para == myChoice;
    }

    //Convert the radiobutton to a number by checking isChecked, if true return the parameter as the convertion result, if false say to DoNothing
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var para = System.Convert.ToInt32(parameter);
        var isChecked = System.Convert.ToBoolean(value);
        return isChecked ? para : Binding.DoNothing;
    }
}

Can anyone help?

I'm guessing I need to make a binding and somehow attach it to .Checked or .isCheck, I tried to with:

//myInt is declared in the Window class with public int myInt {get;set;} and initialized to 0 in the class constructor
Binding myBind = new Binding("myInt");
myBind.Source = myInt;
myBind.Converter = new RadBtnConverter();
myBind.Mode = BindingMode.TwoWay;
myBind.ConverterParameter = 5;

myRadBtn.SetBinding(RadioButton.IsCheckedProperty, myBind);

And though that didn't give any errors, the value of myInt remains at 0.

Community
  • 1
  • 1
Skean
  • 88
  • 6
  • Shouldn't `myBind.Source` be assigned to `this`, i.e. the `Window` instance? Assigning it the current value of the `myInt` property doesn't seem useful. Also, you should of course ensure that the `myInt` property is implemented in a way that supports binding, e.g. as a `DependencyProperty`, having the `Window` implement `IPropertyChanged`, etc. – Peter Duniho Jan 06 '15 at 04:11

1 Answers1

1

The problem with your code is that you assign the current value of the myInt property as the Binding.Source, rather than the object reference for the object where the myInt property is declared.

Here is a code example that does what you're trying to do:

C# code:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public int RadioGroupValue
    {
        get { return (int)GetValue(RadioGroupValueProperty); }
        set { SetValue(RadioGroupValueProperty, value); }
    }

    public static readonly DependencyProperty RadioGroupValueProperty = DependencyProperty.Register("RadioGroupValue", typeof(int), typeof(MainWindow));

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        if (textBox1.Text == "")
        {
            return;
        }

        RadioButton radioButton = new RadioButton();

        radioButton.Content = textBox1.Text;

        Binding binding = new Binding("RadioGroupValue");

        binding.Source = this;
        binding.Converter = new RadioButtonCheckedConverter();
        binding.ConverterParameter = stackPanel1.Children.Count;
        binding.Mode = BindingMode.TwoWay;

        radioButton.SetBinding(RadioButton.IsCheckedProperty, binding);

        stackPanel1.Children.Add(radioButton);
    }
}

class RadioButtonCheckedConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int buttonId = (int)parameter, groupValue = (int)value;

        return buttonId == groupValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int buttonId = (int)parameter;
        bool isChecked = (bool)value;

        return isChecked ? buttonId : Binding.DoNothing;
    }
}

XAML code:

<Window x:Class="TestSO27791757DynamicRadioButton.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        x:Name="mainWindow1">
  <StackPanel>
    <Border BorderBrush="Black" BorderThickness="1" Margin="5" Padding="5">
      <StackPanel Orientation="Horizontal">
        <TextBox x:Name="textBox1" Width="100" Margin="0,0,10,0"/>
        <Button Content="Add RadioButton" Click="Button_Click"/>
        <TextBlock Text="Radio group value: " Margin="10,0,10,0" />
        <TextBox Text="{Binding ElementName=mainWindow1, Path=RadioGroupValue}" />
      </StackPanel>
    </Border>
    <Border BorderBrush="Black" BorderThickness="1" Margin="5" Padding="5">
      <StackPanel x:Name="stackPanel1" />
    </Border>
  </StackPanel>
</Window>

Enter the text for the new RadioButton in the first TextBox, then click the button. A new RadioButton object will be created, correctly bound to the RadioGroupValue property.

There is also a second TextBox bound to the same property. It will show the current radio group value, and you can edit the value there and the radio group state will be updated to reflect that (when focus leaves the TextBox).

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Thank you, this has shown me exactly what I needed to know! I had looked it up, but still didn't really know how to use a DependencyProperty correctly. Additional question, if you feel up to it: I showed the binding to be attaching to a local int property defined within my class to simplify the question. In my project though, I'm trying to attach it to a property of a class that I've got an instance of. I can't add a DependencyProperty to that class though. Is there a way to create one in this Window that links to an objects normal property? – Skean Jan 07 '15 at 00:34
  • @Skean: It depends on what behavior you want. But AFAIK for two-way binding, you'll need one of the supported binding models to be implemented in the bound object: `DependencyProperty`, `INotifyPropertyChanged`, or (if I recall correctly) the older `XXXChanged` event model. I'm relatively new to WPF, but my understanding is that one of the uses of the MVVM pattern is that a view model can wrap an object that doesn't support binding. As long as your program always goes through the view model for property value changes to the underlying object, everything will work. – Peter Duniho Jan 07 '15 at 02:49
  • @Skean: FYI, just tried it and it doesn't look like binding supports the older `XXXChanged` model, at least not through the `Binding` object. – Peter Duniho Jan 07 '15 at 03:04
  • Thanks, I found just binding to the property works, so long as I set the property through the dependency it will update the source and trigger the rest of the interface to update. eg: attaching to `myInstance.myVar` which is just a standard `int myVar {set;get;}` inside the class, using `myDP=DependencyProperty.Register("Var",typeof(int),typeof(MainWindow))` works. The binding then has `Source=myInstance` & `Path="Var"` I can set with `SetValue(myDP,newVal)`. Now I need to find a way to track myDP as it's dynamically created as needed. :s – Skean Jan 07 '15 at 06:41