如何改变在WPF中显示字段的方式?
How to change the way to show a field in WPF?
我有一个在数据库中存储为整数的枚举字段。例如1代表狗,2代表猫。
我想在显示数据时显示真实姓名而不是整数,在 WPF 中执行此操作的最佳做法是什么?
我试过像这样更改 DataSet 中的值 row["TYPE"] = Name[row["TYPE"]];
但它不起作用(不匹配的数据类型)。
数据是用这个ComboBox获取的,数据类型是int
。
<ComboBox Height="23" Name="typeSelectComboBox" Width="190">
<ComboBoxItem Tag="0" Content="Select" />
<ComboBoxItem Tag="1" Content="Foo" />
<ComboBoxItem Tag="2" Content="Bar" />
<ComboBoxItem Tag="3" Content="Cat" />
<ComboBoxItem Tag="4" Content="Dog" />
</ComboBox>
这是我显示数据的方式。
string sqlStr = "select * from AREA";
OracleDataAdapter dataAdapter = new OracleDataAdapter(sqlStr, db.Connection);
DataSet systemDataSet = new DataSet();
dataAdapter.Fill(systemDataSet);
if (systemDataSet.Tables[0].Rows.Count > 0)
{
/* this doesn't work.
foreach (DataRow row in systemDataSet.Tables[0].Rows)
{
// row["TYPE"] = Name[row["TYPE"]];
} */
areaListGrid.ItemsSource = systemDataSet.Tables[0].DefaultView;
}
areaListGrid 只是保存数据的基本 ListGrid
,没有特殊配置。
<DataGrid AutoGenerateColumns="False"
IsReadOnly="True"
Grid.Row="1" Height="484" HorizontalAlignment="Left" Margin="3,4,0,0" Name="areaListGrid" VerticalAlignment="Top" Width="668">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Header="ID" MaxWidth="30" FontSize="12" />
<DataGridTextColumn Binding="{Binding Path=NAME}" MinWidth="50" Header="Name" FontSize="12" />
<DataGridTextColumn Binding="{Binding Path=TYPE}" MinWidth="10" Header="Type" FontSize="12" />
<DataGridTextColumn Binding="{Binding Path=DESCRIPTION}" MinWidth="300" Header="Location" FontSize="12">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Height" Value="Auto"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
我不知道有一种纯粹基于 XAML 的方法可以将一种类型的值映射到另一种类型的值。然而:
- 默认情况下,WPF 中
enum
类型到文本对象的绑定,如 TextBlock.Text
、Button.Content
等,将使用 enum
值名称.在这种情况下,您无事可做。值名称将自动显示为绑定值。
- 如果出于某种原因你绑定的不是实际输入的
enum
,而是普通的 int
,你应该能够实现一个 IValueConverter
映射,以及您在显示对象的绑定声明中使用的映射。
如果您提供显示绑定基本部分的 a good, minimal, complete code example(即 enum
类型和一些显示它的 XAML),则可以提供更具体的答案.
编辑:
不幸的是,问题中的代码示例不完整。也就是说,解决似乎是几个基本问题……
"I don't know how to bind enum to a ComboBox yet"
这个"just works"。例如,这是一个简单的 XAML 形式,其中 TextBlock
用于显示 MainWindow
对象中的当前枚举值,而 ComboBox
其中 Tag
属性 被分配给枚举值本身,就像 Content
属性:
<StackPanel>
<TextBlock Text="{Binding ElementName=mainWindow, Path=Value}" />
<ComboBox SelectionChanged="ComboBox_SelectionChanged" SelectedValuePath="Tag">
<ComboBoxItem Tag="{x:Static local:Fruit.Apple}" Content="{x:Static local:Fruit.Apple}" />
<ComboBoxItem Tag="{x:Static local:Fruit.Orange}" Content="{x:Static local:Fruit.Orange}" />
<ComboBoxItem Tag="{x:Static local:Fruit.Banana}" Content="{x:Static local:Fruit.Banana}" />
<ComboBoxItem Tag="{x:Static local:Fruit.Kiwi}" Content="{x:Static local:Fruit.Kiwi}" />
</ComboBox>
</StackPanel>
(假设声明 enum Fruit { Apple, Orange, Banana, Kiwi }
,当然)
注意使用特定 enum
值的语法:{x:Static local:Fruit.Apple}
。 local
指的是 enum
的命名空间,它在 XAML 根元素的 xmlns
属性中声明(与任何 XAML 命名空间一样),并且当然,enum
值本身就像在 C# 中那样指定(即 <enum name>.<enum value>
)。
TextBlock
直接绑定到 属性,其类型为 Fruit
。
XAML 编译器和 WPF 运行时处理所有其余部分,在向用户显示时将 enum
值转换为其名称,而在显示给用户时使用实际的 enum
值处理代码中的值。
Window
class 看起来像这样:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public Fruit Value
{
get { return (Fruit)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(Fruit), typeof(MainWindow), new PropertyMetadata(Fruit.Apple));
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox comboBox = (ComboBox)sender;
Value = (Fruit)comboBox.SelectedValue;
}
}
即一个正常的基于 DependencyProperty
的 属性,以及一个在选择特定 ComboBoxItem
时更新 属性 值的事件处理程序。
从您的代码示例中不清楚您的 DataAdapter
是如何配置的。但希望它设置为自动将数据库中的整数转换为行中的 enum
类型值。这将是理想的,因为这样您就可以直接将 table 视图绑定到 WPF UI 对象。
如果当前未按此方式设置,我会将您的精力集中在这样做上。但是,如果您确实需要,您应该能够将 IValueConverter
添加到用于在 WPF UI 中显示 table 行的绑定。同样,由于问题缺少有关 areaListGrid
的任何详细信息,我真的不能说您将如何做到这一点。但它会像任何其他 IValueConverter
一样工作:只需编写转换器以从数据库数据中的 int
映射到 enum
名称,然后将其用于数据库列的任何绑定对于那个值。
编辑#2:
如果您实际上没有使用 enum
类型,您可以实现 IValueConverter
来处理显式转换。例如:
class Int32ToValueNameConverter : IValueConverter
{
private static readonly Dictionary<int, string> _intToName = new Dictionary<int, string>()
{
{ 0, "Apple" },
{ 1, "Orange" },
{ 2, "Banana" },
{ 3, "Kiwi" },
};
private static readonly Dictionary<string, int> _nameToInt = _intToName.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is int && targetType == typeof(string))
{
string result;
if (_intToName.TryGetValue((int)value, out result))
{
return result;
}
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string text = value as string;
if (text != null && targetType == typeof(int))
{
int result;
if (_nameToInt.TryGetValue(text, out result))
{
return result;
}
}
return Binding.DoNothing;
}
}
您可以像这样在 XAML 中使用上面的内容:
<StackPanel>
<Button Content="Increment Int" Click="Int32Button_Click" HorizontalAlignment="Left" />
<TextBlock>
<TextBlock.Text>
<Binding ElementName="mainWindow" Path="Int32Value">
<Binding.Converter>
<local:Int32ToValueNameConverter />
</Binding.Converter>
</Binding>
</TextBlock.Text>
</TextBlock>
<TextBox>
<TextBox.Text>
<Binding ElementName="mainWindow" Path="Int32Value" UpdateSourceTrigger="PropertyChanged">
<Binding.Converter>
<local:Int32ToValueNameConverter />
</Binding.Converter>
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
单击该按钮将轮换整数值,在 TextBlock
和 TextBox
中显示结果。在 TextBox
中输入有效的值名称将导致更新绑定 属性,这当然会更新 TextBlock
以反映更改。
支持上述示例的代码隐藏:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public int Int32Value
{
get { return (int)GetValue(Int32ValueProperty); }
set { SetValue(Int32ValueProperty, value); }
}
public static DependencyProperty Int32ValueProperty =
DependencyProperty.Register("Int32Value", typeof(int), typeof(MainWindow), new PropertyMetadata(0));
private void Int32Button_Click(object sender, RoutedEventArgs e)
{
int newValue = Int32Value + 1;
if (newValue > 3)
{
newValue = 0;
}
Int32Value = newValue;
}
}
我相信您可以将上述绑定示例应用到您自己的 DataGrid
场景中,并且请原谅我不想努力生成您的自包含 DataGrid
示例应该有问题,如果提供了答案,我可以以此为基础。
我有一个在数据库中存储为整数的枚举字段。例如1代表狗,2代表猫。
我想在显示数据时显示真实姓名而不是整数,在 WPF 中执行此操作的最佳做法是什么?
我试过像这样更改 DataSet 中的值 row["TYPE"] = Name[row["TYPE"]];
但它不起作用(不匹配的数据类型)。
数据是用这个ComboBox获取的,数据类型是int
。
<ComboBox Height="23" Name="typeSelectComboBox" Width="190">
<ComboBoxItem Tag="0" Content="Select" />
<ComboBoxItem Tag="1" Content="Foo" />
<ComboBoxItem Tag="2" Content="Bar" />
<ComboBoxItem Tag="3" Content="Cat" />
<ComboBoxItem Tag="4" Content="Dog" />
</ComboBox>
这是我显示数据的方式。
string sqlStr = "select * from AREA";
OracleDataAdapter dataAdapter = new OracleDataAdapter(sqlStr, db.Connection);
DataSet systemDataSet = new DataSet();
dataAdapter.Fill(systemDataSet);
if (systemDataSet.Tables[0].Rows.Count > 0)
{
/* this doesn't work.
foreach (DataRow row in systemDataSet.Tables[0].Rows)
{
// row["TYPE"] = Name[row["TYPE"]];
} */
areaListGrid.ItemsSource = systemDataSet.Tables[0].DefaultView;
}
areaListGrid 只是保存数据的基本 ListGrid
,没有特殊配置。
<DataGrid AutoGenerateColumns="False"
IsReadOnly="True"
Grid.Row="1" Height="484" HorizontalAlignment="Left" Margin="3,4,0,0" Name="areaListGrid" VerticalAlignment="Top" Width="668">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Header="ID" MaxWidth="30" FontSize="12" />
<DataGridTextColumn Binding="{Binding Path=NAME}" MinWidth="50" Header="Name" FontSize="12" />
<DataGridTextColumn Binding="{Binding Path=TYPE}" MinWidth="10" Header="Type" FontSize="12" />
<DataGridTextColumn Binding="{Binding Path=DESCRIPTION}" MinWidth="300" Header="Location" FontSize="12">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Height" Value="Auto"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
我不知道有一种纯粹基于 XAML 的方法可以将一种类型的值映射到另一种类型的值。然而:
- 默认情况下,WPF 中
enum
类型到文本对象的绑定,如TextBlock.Text
、Button.Content
等,将使用enum
值名称.在这种情况下,您无事可做。值名称将自动显示为绑定值。 - 如果出于某种原因你绑定的不是实际输入的
enum
,而是普通的int
,你应该能够实现一个IValueConverter
映射,以及您在显示对象的绑定声明中使用的映射。
如果您提供显示绑定基本部分的 a good, minimal, complete code example(即 enum
类型和一些显示它的 XAML),则可以提供更具体的答案.
编辑:
不幸的是,问题中的代码示例不完整。也就是说,解决似乎是几个基本问题……
"I don't know how to bind enum to a ComboBox yet"
这个"just works"。例如,这是一个简单的 XAML 形式,其中 TextBlock
用于显示 MainWindow
对象中的当前枚举值,而 ComboBox
其中 Tag
属性 被分配给枚举值本身,就像 Content
属性:
<StackPanel>
<TextBlock Text="{Binding ElementName=mainWindow, Path=Value}" />
<ComboBox SelectionChanged="ComboBox_SelectionChanged" SelectedValuePath="Tag">
<ComboBoxItem Tag="{x:Static local:Fruit.Apple}" Content="{x:Static local:Fruit.Apple}" />
<ComboBoxItem Tag="{x:Static local:Fruit.Orange}" Content="{x:Static local:Fruit.Orange}" />
<ComboBoxItem Tag="{x:Static local:Fruit.Banana}" Content="{x:Static local:Fruit.Banana}" />
<ComboBoxItem Tag="{x:Static local:Fruit.Kiwi}" Content="{x:Static local:Fruit.Kiwi}" />
</ComboBox>
</StackPanel>
(假设声明 enum Fruit { Apple, Orange, Banana, Kiwi }
,当然)
注意使用特定 enum
值的语法:{x:Static local:Fruit.Apple}
。 local
指的是 enum
的命名空间,它在 XAML 根元素的 xmlns
属性中声明(与任何 XAML 命名空间一样),并且当然,enum
值本身就像在 C# 中那样指定(即 <enum name>.<enum value>
)。
TextBlock
直接绑定到 属性,其类型为 Fruit
。
XAML 编译器和 WPF 运行时处理所有其余部分,在向用户显示时将 enum
值转换为其名称,而在显示给用户时使用实际的 enum
值处理代码中的值。
Window
class 看起来像这样:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public Fruit Value
{
get { return (Fruit)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(Fruit), typeof(MainWindow), new PropertyMetadata(Fruit.Apple));
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox comboBox = (ComboBox)sender;
Value = (Fruit)comboBox.SelectedValue;
}
}
即一个正常的基于 DependencyProperty
的 属性,以及一个在选择特定 ComboBoxItem
时更新 属性 值的事件处理程序。
从您的代码示例中不清楚您的 DataAdapter
是如何配置的。但希望它设置为自动将数据库中的整数转换为行中的 enum
类型值。这将是理想的,因为这样您就可以直接将 table 视图绑定到 WPF UI 对象。
如果当前未按此方式设置,我会将您的精力集中在这样做上。但是,如果您确实需要,您应该能够将 IValueConverter
添加到用于在 WPF UI 中显示 table 行的绑定。同样,由于问题缺少有关 areaListGrid
的任何详细信息,我真的不能说您将如何做到这一点。但它会像任何其他 IValueConverter
一样工作:只需编写转换器以从数据库数据中的 int
映射到 enum
名称,然后将其用于数据库列的任何绑定对于那个值。
编辑#2:
如果您实际上没有使用 enum
类型,您可以实现 IValueConverter
来处理显式转换。例如:
class Int32ToValueNameConverter : IValueConverter
{
private static readonly Dictionary<int, string> _intToName = new Dictionary<int, string>()
{
{ 0, "Apple" },
{ 1, "Orange" },
{ 2, "Banana" },
{ 3, "Kiwi" },
};
private static readonly Dictionary<string, int> _nameToInt = _intToName.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is int && targetType == typeof(string))
{
string result;
if (_intToName.TryGetValue((int)value, out result))
{
return result;
}
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string text = value as string;
if (text != null && targetType == typeof(int))
{
int result;
if (_nameToInt.TryGetValue(text, out result))
{
return result;
}
}
return Binding.DoNothing;
}
}
您可以像这样在 XAML 中使用上面的内容:
<StackPanel>
<Button Content="Increment Int" Click="Int32Button_Click" HorizontalAlignment="Left" />
<TextBlock>
<TextBlock.Text>
<Binding ElementName="mainWindow" Path="Int32Value">
<Binding.Converter>
<local:Int32ToValueNameConverter />
</Binding.Converter>
</Binding>
</TextBlock.Text>
</TextBlock>
<TextBox>
<TextBox.Text>
<Binding ElementName="mainWindow" Path="Int32Value" UpdateSourceTrigger="PropertyChanged">
<Binding.Converter>
<local:Int32ToValueNameConverter />
</Binding.Converter>
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
单击该按钮将轮换整数值,在 TextBlock
和 TextBox
中显示结果。在 TextBox
中输入有效的值名称将导致更新绑定 属性,这当然会更新 TextBlock
以反映更改。
支持上述示例的代码隐藏:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public int Int32Value
{
get { return (int)GetValue(Int32ValueProperty); }
set { SetValue(Int32ValueProperty, value); }
}
public static DependencyProperty Int32ValueProperty =
DependencyProperty.Register("Int32Value", typeof(int), typeof(MainWindow), new PropertyMetadata(0));
private void Int32Button_Click(object sender, RoutedEventArgs e)
{
int newValue = Int32Value + 1;
if (newValue > 3)
{
newValue = 0;
}
Int32Value = newValue;
}
}
我相信您可以将上述绑定示例应用到您自己的 DataGrid
场景中,并且请原谅我不想努力生成您的自包含 DataGrid
示例应该有问题,如果提供了答案,我可以以此为基础。