使用整数字段和枚举作为显示名称填充 DataGridComboBoxColumn
Posted
技术标签:
【中文标题】使用整数字段和枚举作为显示名称填充 DataGridComboBoxColumn【英文标题】:Populate DataGridComboBoxColumn using integer fields and an enum as it's display name 【发布时间】:2021-02-27 10:31:08 【问题描述】:我从包含用户数组的数据库中收到一个查询,在用户类中我有一个名为 Role
的字节字段。我希望我的DataGridComboBoxColumn
有 2 个项目。如果Role == 0
是"Member"
,如果Role == 1
是"Moderator"
。
User.cs
public enum UserRole
Member,
Moderator
public class User
[JsonConstructor]
public User(int userId, string email, string password, string token, string nickname, byte role, uint coins, int power1, int power2, int power3, int power4, DateTime createTime, DateTime? lastLoginTime)
this.UserId = userId;
this.Email = email;
this.Password = password;
this.Token = token;
this.Nickname = nickname;
this.Role = role;
this.Coins = coins;
this.Power1 = power1;
this.Power2 = power2;
this.Power3 = power3;
this.Power4 = power4;
this.CreateTime = createTime;
this.LastLoginTime = lastLoginTime;
this.UserRole = (UserRole)role;
[JsonPropertyName("userId")]
public int UserId get; set;
[JsonPropertyName("email")]
public string Email get; set;
[JsonPropertyName("password")]
public string Password get; set;
[JsonPropertyName("token")]
public string Token get; set;
[JsonPropertyName("nickname")]
public string Nickname get; set;
[JsonPropertyName("role")]
public byte Role get; set;
[JsonPropertyName("coins")]
public uint Coins get; set;
[JsonPropertyName("power1")]
public int Power1 get; set;
[JsonPropertyName("power2")]
public int Power2 get; set;
[JsonPropertyName("power3")]
public int Power3 get; set;
[JsonPropertyName("power4")]
public int Power4 get; set;
[JsonPropertyName("createTime")]
public DateTime CreateTime get; set;
[JsonPropertyName("lastLoginTime")]
public DateTime? LastLoginTime get; set;
[JsonIgnore]
public UserRole UserRole get; set;
MainWindow.xaml
<materialDesign:DataGridComboBoxColumn
Header="Role"
Width="100">
<materialDesign:DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox" BasedOn="StaticResource ComponentResourceKey TypeInTargetAssembly=x:Type ComboBox, ResourceId=MaterialDataGridComboBoxColumnEditingStyle" >
<Setter Property="IsEditable" Value="True" />
<Setter Property="ItemsSource" Value="Binding RelativeSource=RelativeSource AncestorType=x:Type DataGrid, Path=DataContext.Role"/>
<Setter Property="DisplayMemberPath" Value="UserRole"/>
</Style>
</materialDesign:DataGridComboBoxColumn.EditingElementStyle
</materialDesign:DataGridComboBoxColumn>
【问题讨论】:
【参考方案1】:您的代码和 XAML 中有多个问题需要解决。
数据网格列不是可视树的一部分,这意味着您的绑定DataContext.Role
等相对源和元素名称绑定将不起作用。
您的UserRole
类型是enum
,但您希望在组合框列中将其常量名称显示为可供选择的项目。 ItemsSource
属性需要一个可枚举类型,而枚举不是。
我假设您将User
s 的数组或集合绑定到您的数据网格。这意味着您的列的数据上下文是 User
实例。在这种情况下,您的组合框 ItemsSource
绑定没有意义,因为您正在尝试绑定不包含当前用户的数据网格数据上下文,即使它包含,Role
属性也是 byte
,而不是可枚举的。
您将DisplayMemberPath
设置为UserRole
,但它不起作用,因为您想将您的组合框绑定到不包含属性UserRole
的UserRole
枚举的常量。
您的User
类型包含byte
类型的Role
,以及UserRole
类型的UserRole
。目前尚不清楚您要使用两者的哪个属性以及另一个用于什么。
您的枚举类型具有underlying type int
, which is the default。如果您在内部使用值作为 byte
无论如何,您可以考虑将其更改为 byte
。
你只设置了编辑样式,没有设置非编辑样式,进入编辑模式时会弹出值,离开编辑模式时会隐藏。
您设置了DisplayMemberPath
,但我认为您真正想做的是将Role
属性绑定为选定项。
在下文中,我假设您希望使用 byte
类型的 Role
属性进行绑定,并且您希望在组合框列中显示 UserRole
枚举的常量名称。
首先,您必须创建一个枚举常量。您可以在代码中提供一个可以绑定的集合,但由于它永远不会更改并且当前仅在数据网格中使用,您可以像这样create it entirely in XAML using an ObjectDataProvider
:
<ObjectDataProvider x:Key="UserRoles" MethodName="GetValues" ObjectType="x:Type system:Enum">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:UserRole"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
接下来,我们需要创建一个转换器,将byte
转换为UserRole
并返回。
public class UserRoleToEnumConverter : IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
return (UserRole)System.Convert.ToByte(value);
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
return (byte)(int)value;
现在让我们将它们放在一个数据网格中并绑定到Role
属性。
<DataGrid ItemsSource="Binding Users" AutoGenerateColumns="False">
<DataGrid.Resources>
<local:UserRoleToEnumConverter x:Key="UserRoleToEnumConverter"/>
<ObjectDataProvider x:Key="UserRoles" MethodName="GetValues" ObjectType="x:Type system:Enum">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:UserRole"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</DataGrid.Resources>
<DataGrid.Columns>
<materialDesign:DataGridComboBoxColumn Header="Role"
IsEditable="True"
Width="100">
<materialDesign:DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox" BasedOn="StaticResource ComponentResourceKey TypeInTargetAssembly=x:Type ComboBox, ResourceId=MaterialDataGridComboBoxColumnEditingStyle" >
<Setter Property="IsEditable" Value="True" />
<Setter Property="ItemsSource" Value="Binding Source=StaticResource UserRoles"/>
<Setter Property="SelectedItem" Value="Binding Role, Converter=StaticResource UserRoleToEnumConverter"/>
</Style>
</materialDesign:DataGridComboBoxColumn.EditingElementStyle>
</materialDesign:DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
正如我上面已经提到的,由于您只调整编辑样式,您的列可能不会像您预期的那样表现。我建议您根本不要编辑样式,而是在列上设置绑定:
<materialDesign:DataGridComboBoxColumn Header="Role"
IsEditable="True"
Width="100"
ItemsSource="Binding Source=StaticResource UserRoles"
SelectedItemBinding="Binding Role, Converter=StaticResource UserRoleToEnumConverter"/>
这种方法可以满足您的要求,但是使用枚举常量直接显示 UI 文本是不好的。考虑本地化和具有多个作品的项目。您不会显示驼峰式文本。展望未来,也许您应该考虑使用更灵活、更强大的解决方案。
【讨论】:
做那个人一定感觉很好【参考方案2】:因为你已经有一个用于从数据库中转换字节值的枚举,你只需要一个专用的转换:
public class UserRoleToStringConverter : IValueConverter
/// <summary>
/// Converts a value.
/// </summary>
/// <param name="value">The value produced by the binding source.</param>
/// <param name="targetType">The type of the binding target property.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
var enumValue = UserRole.Member;
if (value is UserRole)
enumValue = (UserRole)value;
switch (enumValue)
case UserRole.Member: return "Member";
case UserRole.Role: return "Moderator";
/// <summary>
/// Converts a value.
/// </summary>
/// <param name="value">The value that is produced by the binding target.</param>
/// <param name="targetType">The type to convert to.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
/// <exception cref="NotImplementedException"></exception>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
throw new NotImplementedException();
请注意,通过查看CultureInfo
转换器参数,如果需要,您可能会本地化您的字符串。
另一种方法可能是绑定 ViewModel 的 string
属性,以便 XAML 并在 ViewModel 中添加字符串转换。
【讨论】:
感谢您的回答,如何在我的 xaml 代码中使用它? 请关注***.com/questions/9448862/… 此处的帖子,该帖子让您描述在使用您使用的 DisplayMemberPath 方法时如何使用转换器。以上是关于使用整数字段和枚举作为显示名称填充 DataGridComboBoxColumn的主要内容,如果未能解决你的问题,请参考以下文章
用python.检查“影片名称”字段为空值的+数据,给该字段填充数+据"unnamed"?
C# Windows 窗体(非 SQL):在新窗体上用整数 +1 填充 DataGridView 行中当前最高数字的文本框