如何改变在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.TextButton.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>

单击该按钮将轮换整数值,在 TextBlockTextBox 中显示结果。在 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 示例应该有问题,如果提供了答案,我可以以此为基础。