<Grid Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="4">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="DayButtons"/>
<!-- and so on-->
</Grid.ColumnDefinitions>
<ToggleButton Grid.Column="0" IsChecked="{Binding blah blah blah Converter=Whatever, ConverterParameter={x: Static TooFreakingLong}">Monday</ToggleButton>
<!-- and so on -->
</Grid>
So I've defined an enum for the days of the week, and although I can make a simple Grid to show all the days of the week and toggle them at will (think for a recurring calendar day app). However, I want to apply this pattern to other [Flags]
enums in my app and I don't want to write all this boiler #plate code over and over again. Any suggestions? Thanks!
This should work. The MarkupExtension
enumerates the values of any enum type you give it, and once you've got that, you can do anything you like in an ItemsControl
or any appropriate subclass like ListBox
. I've written a MultiDataConverter as well, which takes a single enum flag and checks to see if it's included in a set of flags. Given that, you can write a trigger to do just about anything.
If you want the values to be always visible and be included/excluded from the set of flags by (for example) a checkbox in the item DataTemplate, that would be another MultiDataConverter.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Markup;
namespace EdTest
{
[Flags]
public enum TestEnum
{
Foo = 1 << 0,
Bar = 1 << 1,
Baz = 1 << 2,
Ping = 1 << 3,
Pong = 1 << 4,
Hoop = 1 << 5,
Floop = 1 << 6
};
public class EnumEnumerator : MarkupExtension
{
public EnumEnumerator(Type type)
{
_type = type;
}
private Type _type;
public override object ProvideValue(IServiceProvider serviceProvider)
{
return Enum.GetValues(_type);
}
}
}
...and in the XAML, any control that displays collections can display it in any appropriate template. You could write ValueConverters
to do more stuff with the enum values themselves.
<ItemsControl
xmlns:test="clr-namespace:EdTest"
ItemsSource="{test:EnumEnumerator test:TestEnum}"
>
<ItemsControl.Resources>
<test:FlagCheckConverter x:Key="FlagChecker" />
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border
x:Name="Border"
Padding="6"
Width="80"
Height="60"
BorderBrush="SteelBlue"
BorderThickness="1,1,0,0"
>
<ContentControl Content="{Binding}" />
</Border>
<DataTemplate.Triggers>
<DataTrigger Value="False">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource FlagChecker}">
<!-- The DataContext value - a single enum value -->
<Binding />
<Binding
Path="DataContext.TestFlags"
RelativeSource="{RelativeSource AncestorType=ItemsControl}"
/>
</MultiBinding>
</DataTrigger.Binding>
<Setter TargetName="Border" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel
Orientation="Horizontal"
/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
And here's the MultiDataConverter that checks to see if a given enum value is one of a set of flags:
public class FlagCheckConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, CultureInfo culture)
{
var checkValue = values[0];
var flags = values[1];
if (checkValue is Enum && flags is Enum)
{
return ((Enum)flags).HasFlag((Enum)checkValue);
}
return (object)false;
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}