dharmatech
dharmatech

Reputation: 9537

Creating RadioButtons from an enum in C#

I'd like to populate a StackPanel with RadioButton objects which correspond to the values of an enum. Each button's handler should run an arbitrary computation which takes the corresponding enum val.

Here's the method I came up with:

void EnumToRadioButtonPanel(Panel panel, Type type, Action<int> proc)
{
    Array.ForEach((int[])Enum.GetValues(type),
        val =>
        {
            var button = new RadioButton() { Content = Enum.GetName(type, val) };
            button.Click += (s, e) => proc(val);
            panel.Children.Add(button);
        });
}

For example, let's say I want RadioButtons for the enum FigureHorizontalAnchor. I'd like the action of each button to set the HorizontalAnchor property of a particular Figure called figure. Here's how I'd invoke EnumToRadioButtonPanel:

var figure = new Figure();

var stackPanel = new StackPanel();

EnumToRadioButtonPanel(stackPanel, typeof(FigureHorizontalAnchor),
    val =>
    {
        figure.HorizontalAnchor = (FigureHorizontalAnchor)
            Enum.ToObject(typeof(FigureHorizontalAnchor), val);
    });

My question is, is there a better way to accomplish this? Should I be using "binding" techniques instead? I've seen a couple of related questions here on SO, but they involved laying out the RadioButtons in XAML; I'd like to do this via the code behind in C#.

Here's a complete runnable demo of the above. XAML:

<Window x:Class="EnumToRadioButtonPanel.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">

</Window>

Code behind:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace EnumToRadioButtonPanel
{
    public partial class MainWindow : Window
    {
        void EnumToRadioButtonPanel(Panel panel, Type type, Action<int> proc)
        {
            Array.ForEach((int[])Enum.GetValues(type),
                val =>
                {
                    var button = new RadioButton() { Content = Enum.GetName(type, val) };
                    button.Click += (s, e) => proc(val);
                    panel.Children.Add(button);
                });
        }

        public MainWindow()
        {
            InitializeComponent();

            var figure = new Figure();

            var stackPanel = new StackPanel();

            Content = stackPanel;

            EnumToRadioButtonPanel(stackPanel, typeof(FigureHorizontalAnchor),
                val =>
                {
                    figure.HorizontalAnchor = (FigureHorizontalAnchor)
                        Enum.ToObject(typeof(FigureHorizontalAnchor), val);
                });

            var label = new Label();

            stackPanel.Children.Add(label);

            var button = new Button() { Content = "Display" };

            button.Click += (s, e) => label.Content = figure.HorizontalAnchor;

            stackPanel.Children.Add(button);
        }
    }
}

Upvotes: 1

Views: 1609

Answers (2)

dharmatech
dharmatech

Reputation: 9537

Here's another version of EnumToRadioButtonPanel which seems to lead to cleaner code by being generic over the type.

void EnumToRadioButtonPanel<T>(Panel panel, Action<T> proc)
{
    Array.ForEach((int[])Enum.GetValues(typeof(T)),
        val =>
        {
            var button = new RadioButton() { Content = Enum.GetName(typeof(T), val) };
            button.Click += (s, e) => proc((T)Enum.ToObject(typeof(T),val));
            panel.Children.Add(button);
        });
}

With this version, the call to EnumToRadioButtonPanel looks like this:

EnumToRadioButtonPanel<FigureHorizontalAnchor>(
    stackPanel,
    val => figure.HorizontalAnchor = val);

instead of:

EnumToRadioButtonPanel(stackPanel, typeof(FigureHorizontalAnchor),
    val =>
    {
        figure.HorizontalAnchor = (FigureHorizontalAnchor)
            Enum.ToObject(typeof(FigureHorizontalAnchor), val);
    });

Below is the entire example. XAML:

<Window x:Class="EnumToRadioButtonPanel.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">

</Window>

C#:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace EnumToRadioButtonPanel
{
    public partial class MainWindow : Window
    {
        void EnumToRadioButtonPanel<T>(Panel panel, Action<T> proc)
        {
            Array.ForEach((int[])Enum.GetValues(typeof(T)),
                val =>
                {
                    var button = new RadioButton() { Content = Enum.GetName(typeof(T), val) };
                    button.Click += (s, e) => proc((T)Enum.ToObject(typeof(T),val));
                    panel.Children.Add(button);
                });
        }

        public MainWindow()
        {
            InitializeComponent();

            var figure = new Figure();

            var stackPanel = new StackPanel();

            Content = stackPanel;

            EnumToRadioButtonPanel<FigureHorizontalAnchor>(
                stackPanel,
                val => figure.HorizontalAnchor = val);

            var label = new Label();

            stackPanel.Children.Add(label);

            var button = new Button() { Content = "Display" };

            button.Click += (s, e) => label.Content = figure.HorizontalAnchor;

            stackPanel.Children.Add(button);
        }
    }
}

Upvotes: 0

Nicolas Repiquet
Nicolas Repiquet

Reputation: 9265

As you suggest, there is more "WPF" ways to do it.

Do not create controls by code. It was somewhat ok with WinForms, but it's not how you wanna do it in WPF.

If you want to create a collection of controls out of a list of item, use ItemsControl:

<ItemsControl Source="{Binding ItemsIWantToCreateControlsFor}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <RadioButton
        Content="{Binding APropertyDefinedInMyItem}"
        Command="{Binding ACommandDefinedInMyItemThatIsExecutedWhenPressed}"/>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

Upvotes: 3

Related Questions