如何在WPF中为[Flags]枚举制作通用开关?

时间:2016-03-29 19:30:15

标签: c# wpf data-binding enums enum-flags

<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>

所以我已经为一周的日子定义了一个枚举,虽然我可以制作一个简单的网格来显示一周中的所有日子并随意切换它们(想想一个重​​复的日历日应用程序)。但是,我想将此模式应用于我的应用程序中的其他[Flags]枚举,我不想一遍又一遍地写所有这些锅炉#plate代码。有什么建议?谢谢!

1 个答案:

答案 0 :(得分:2)

这应该有效。 MarkupExtension枚举您提供的任何枚举类型的值,一旦得到它,您可以在ItemsControl或任何适当的子类(如ListBox)中执行任何您喜欢的操作。我也编写了一个MultiDataConverter,它接受一个枚举标志并检查它是否包含在一组标志中。鉴于此,您可以编写触发器来执行任何操作。

如果您希望值始终可见并通过(例如)DataTemplate项中的复选框从标志集中包含/排除,那将是另一个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);
        }
    }
}

...在XAML中,任何显示集合的控件都可以在任何适当的模板中显示它。您可以编写ValueConverters来使用枚举值本身执行更多操作。

<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>

这是MultiDataConverter,它检查给定的枚举值是否是一组标志之一:

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();
    }
}