【问题标题】:How can I get a WPF DataGrid column to bind to an enumeration?如何让 WPF DataGrid 列绑定到枚举?
【发布时间】:2019-11-30 09:05:49
【问题描述】:

我有一组已绑定到 WPF DataGrid 的项目。其中一列需要允许用户从枚举中进行选择。我还创建了一个单独的类来为每个枚举值保存用户友好的显示字符串。

这些是类型:

public enum UnitEnum { Metres, Hours, SingleValue };

public class UnitTuple
{
    public UnitEnum Unit { get; set; }
    public string DisplayName { get; set; }
}

public class CostItem
{
    public string Name { get; set; }
    public UnitEnum UnitID { get; set; }
}

这是我的视图模型:

public static List<UnitTuple> AllUnitTuples = new List<UnitTuple>()
{
    new UnitTuple { Unit = UnitEnum.Metres, DisplayName = "Metres" },
    new UnitTuple { Unit = UnitEnum.Hours, DisplayName = "Hours" },
    new UnitTuple { Unit = UnitEnum.SingleValue, DisplayName = "Single Value" }
};

public List<CostItem> CostItems => new List<CostItem>()
{
    new CostItem() { Name = "Design", UnitID = UnitEnum.SingleValue },
    new CostItem() { Name = "Manufacturing", UnitID = UnitEnum.Hours },
    new CostItem() { Name = "Materials", UnitID = UnitEnum.Metres }
};

这是我正在使用的 XAML 的开始:

<DataGrid x:Name="DataGridCostItems"
    ItemsSource="{Binding CostItems}"
    AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Cost Item Name" Binding="{Binding Name}"/>
        <DataGridComboBoxColumn Header="Units"/>
    </DataGrid.Columns>
</DataGrid>

谁能帮我解决剩下的数据绑定表达式(例如ItemsSourceSelectedValueBinding)?

我一直在尝试遵循下面显示的两个示例,但在将这些示例映射到我的代码时遇到了麻烦。

Codeless two-way data binding

How to bind an enumerator

根据 Aakanksha 的回答,我试图让 ObjectDataProvider 工作但不能。我遇到的问题——DataGridComboBoxColumn 显然没有视图模型的数据上下文——在这里解释:Cannot find governing FrameworkElement

同一篇文章建议改用CollectionViewSource。尝试这个解决方案导致下面的代码几乎可以工作:组合框列正确填充了用户友好的显示字符串,当我选择一个进行编辑时,我得到一个包含用户友好显示字符串的下拉列表为枚举。都很好。

我现在唯一无法终生工作的部分是让组合框中新选择的值保持回数据绑定的CostItem

谁能建议如何解决最后一个难题?

public enum CostUnit
{
    SingleValue,
    Hours,
    Metres
}

public class CostUnitTuple
{
    public EstimateCostUnitTuple( EstimateCostUnit enumValue, string displayString )
    {
        EnumValue = enumValue;
        DisplayString = displayString;
    }

    public CostUnit EnumValue { get; private set; }

    public string DisplayString { get; private set; };
}

public static class CostUnitAllTuples
{
    public static string GetDisplayStringFromEnum( CostUnit enumValue ) { ... }

    public static CostUnit GetEnumFromDisplayString( string displayString ) { ... }

    public static CostUnitTuple[] GetValues => new CostUnitTuple[]
    {
        new CostUnitTuple( CostUnit.Hours, "Hours" ),
        new CostUnitTuple( CostUnit.Metres, "Metres" ),
        new CostUnitTuple( CostUnit.SingleValue, "Single Value" )
    };
}

public class CostItem
{
    public string Name { get; set; } = "";

    public CostUnit Units
    {
        get => _units;
        set
        {
            _units = value;
            UnitDisplayString = CostUnitAllTuples.GetDisplayStringFromEnum( _units );
        }
    }

    public string UnitDisplayString { get; private set; } = "";

    private CostUnit _units;
}

public class UnitsOfMeasureConverter : IValueConverter
{
    public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
        CostUnitAllTuples.GetDisplayStringFromEnum( (CostUnit)value );

    public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) =>
                    ((EstimateCostUnitTuple)value).EnumValue;
}

public class ViewModel
{
    public List<CostItem> CostItems { get; set; } 
    public AllCostUnits => CostUnitAllTuples.GetValues;
}

<Control.Resources>
    <ResourceDictionary>
        <u:UnitsOfMeasureConverter x:Key="UnitsOfMeasureConverterKey"/>
        <CollectionViewSource x:Key="UnitsCollectionViewSourceKey" Source="{Binding AllCostUnits}"/>
    </ResourceDictionary>
</Control.Resources>

<DataGrid
    ItemsSource="{Binding CostItems}"
    SelectionMode="Single">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
            <DataGridComboBoxColumn Header="Units"
                TextBinding="{Binding UnitDisplayString,Mode=OneWay}"
                SelectedItemBinding="{Binding Units,Converter={StaticResource UnitsOfMeasureConverterKey}}"
                DisplayMemberPath="DisplayString"
                ItemsSource="{Binding Source={StaticResource UnitsCollectionViewSourceKey}}"/>
        </DataGrid.Columns>
</DataGrid>

【问题讨论】:

    标签: wpf xaml data-binding datagrid


    【解决方案1】:

    您可以使用转换器在数据网格中显示枚举。

    public class EnumConverter : IValueConverter
    {
    
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((Enum)value).ToString()
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return  null;
        }
    }
    

    在您的 XAML 中,类似这样的内容:

    Binding="{Binding UnitID, Converter="{StaticResource ResourceKey=EnumConverter}}" 
    

    在 xaml 文件的资源部分声明您的“EnumConverter”。

    【讨论】:

    • 我不认为缺少转换器是我的问题的主要部分。如果我将代码中的所有枚举都更改为整数,我仍然无法让它工作。 (但是 +1 因为,是的,我无疑需要一个转换器或 ToString() 在某处覆盖。)
    【解决方案2】:

    其中一种方式是:

    <DataGridTemplateColumn>
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <ComboBox ItemsSource="{x:Static local:YourViewModelClassName.AllUnitTuples}" SelectedValuePath="Unit" SelectedValue="{Binding UnitID, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    

    【讨论】:

    • 我现在就试试这个。但它确实感觉像是一个二等解决方案,因为 DataGrid 已经有一个组合框列类型,它似乎是专门为做我想要的而设计的。我想让它发挥作用,就像未来的知识一样。
    【解决方案3】:

    将枚举绑定到您的DataGridComboBox

    在资源部分添加ObjectDataProvider

    <Window.Resources>
        <ObjectDataProvider x:Key="myEnumData" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:UnitEnum" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
    

    并且在DataGridComboBoxColumn中绑定ItemsSource这样,

    <DataGridComboBoxColumn Header="MyHeader" DisplayMemberPath="EnumValue" ItemsSource="{Binding Source={StaticResource myEnumData}}" SelectedItemBinding="{Binding UnitID}"/>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-03
      • 1970-01-01
      • 2015-07-03
      • 2016-03-26
      • 1970-01-01
      • 2010-10-09
      • 2011-01-30
      相关资源
      最近更新 更多