Reputation: 9537
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 RadioButton
s 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 RadioButton
s 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
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
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