【问题标题】:Why Convert method is used to ConvertBack a value in WPF combobox?为什么使用 Convert 方法将 WPF 组合框中的值转换回?
【发布时间】:2011-07-06 07:17:22
【问题描述】:

确切的问题是——为什么使用 Convert 而不是 ConvertBack,为什么这里首先需要 ConvertBack?

问题

以下是我的问题示例,我试图简化事情。这是普通的 WPF,没有 3rd 方库,问题本身是经典的主从细节,有点扭曲。

我有列表框(城市列表)和数据网格(列出我所有的朋友+电话)。当我选择列表框时,数据网格应该刷新并显示来自所选城市的人。数据网格如下所示:

Name | Phone | PhoneType
Mark | 76447 | cellphone
...

这里的关键问题是 PhoneType 列。每个单元格应该是一个组合框,其中填充了预定义的电话类型(从数据库中获取)。扭曲在于 db 结构。是这样的:

typeID | PhoneType | PhoneDescription
1      | cellphone | NULL
2      | neighbour | call only in case of emergency

在我的数据网格组合框中,PhoneType 应该显示BUT,如果 PhoneDescription 存在,则应该使用它而不是普通的 PhoneType。

问题结束。你和我一起吗?

实施

为了在数据网格中有组合框,我必须使用带有组合框的模板列,而不是组合框数据网格列(原因如下:WPF Datagrid ComboBox DataBinding)。所以这是我的组合框:

<ComboBox ItemsSource="{Binding Path=PhoneTypesList, 
          RelativeSource={RelativeSource AncestorType={x:Type Window}}}"  

好的,这里(上图)我定义了应该在 Combobox 下拉列表中列出的内容。 PhoneType 记录列表(在数据库意义上)。

          SelectedValuePath="typeID"
          SelectedValue="{Binding Path=typeID}">

Combobox 应该知道我朋友的电话类型的当前值,所以这里(上图)是我绑定这些值的方式——一方面我设置了 PhoneType 记录中的 typeID 应该用于匹配,另一方面手我设置应该使用来自 Friend 记录的 typeID。这样,WPF 就知道应该将哪个电话类型记录用作当前值。

(如果您不是 100% 熟悉此绑定,这里有一个很好的解释: Difference between SelectedItem, SelectedValue and SelectedValuePath)

顺便说一句。 typeID 使用了两次,因为通常我更喜欢在数据库中的相关字段(外键字段)中使用完全相同的名称。

我有列表,我已经完成了匹配,现在——为了显示,我不能只使用 DisplayMemberPath,因为我需要更动态的东西。

  <ComboBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Converter={StaticResource PhoneTypeConverter}}"/>
    </DataTemplate>
  </ComboBox.ItemTemplate>
</ComboBox>

所以要显示 PhoneType,我会获取整个记录并选择适当的字符串。

[ValueConversion(typeof(PhoneTypeRecord), typeof(string))]
public class PhoneTypeConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        if (value == null)
            return null;

        var record = ((PhoneTypeRecord)value); // crash!
        return record.PhoneDescription ?? record.PhoneType;
    }

    // we don't do any conversion back
    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
            return null;
    }
}

错误

我编译整个应用程序,我运行它,我点击任何城市。它按预期工作,很棒。

然后我点击另一个城市。应用程序思考了一下,然后在刷新城市列表框或数据网格之前,它崩溃并出现异常(参见上面的标记行)说:

无法转换类型的对象 'System.String' 键入 'MyBuilderApp.PhoneTypeRecord'。

我不知道发生了什么。为什么字符串被传递给转换???它看起来更像是 ConvertBack。

【问题讨论】:

  • 在你的转换器中设置一个断点,看看给出的是什么字符串。这可能有助于您识别问题。
  • @Rachel,你在 VS 中强制断点异常 ;-) 空(非空)字符串。

标签: c# wpf data-binding ivalueconverter


【解决方案1】:

我认为在这种情况下,您使用PriorityBinding 会容易得多。它将处理描述为空的情况,并为您使用类型:

<ComboBox>
  <ComboBox.ItemTemplate>
    <DataTemplate>
      <TextBlock>
         <TextBlock.Text>
           <PriorityBinding>
             <Binding Path="PhoneDescription" />
             <Binding Path="PhoneType" />
           </PriorityBinding>
         </TextBlock.Text>
      </TextBlock>
    </DataTemplate>
  </ComboBox.ItemTemplate>
</ComboBox>

【讨论】:

  • 感谢您采用这种方法,但总的来说,我想了解事情的运作方式。这里真的很奇怪,Convert 用于转换回(!)数据。
  • 好吧,我不能完全确定为什么在选择另一个项目后将字符串传递给转换器,但是绑定的 DataContext 以某种方式更改为字符串。如果您的转换器执行“as”强制转换,并在它为 null 时返回,它可能会起作用。
【解决方案2】:

在我看来,文本块绑定到从 PhoneTypesList 返回的内容。然后在此使用转换器,它需要一个 PhoneTypeRecord。 我想 PhoneTypesList 是 PhoneTypeRecord 的列表,对吗? 我注意到的是,在转换器中,我得到的是完整列表,而不是列表中的每个元素。所以你实际上得到了PhoneTypeRecord的列表/集合/observableCollection。验证一下。

您也可以在转换器中添加这样的条件:

if(value != typeof(what_you_are_expecting) throw new InvalidOperationException("something is wrong");

【讨论】:

  • TextBlock 被“绑定”到 PhoneTypesList 的元素,而不是整个集合。 “PhoneTypesList 是 PhoneTypeRecord 的列表”——正确。 “在转换器中,我得到的是完整列表,而不是列表中的每个元素”——不正确。它是 TextBlock 值的转换器,而不是 ItemsSource 转换器(用于整个组合框)。关于检查传入的类型——第一次点击后它只是 PhoneTypeRecord (多次,每次列表中的每个元素)。在第二次点击时,第一个进来的类型是字符串。
猜你喜欢
  • 2011-02-18
  • 2017-02-05
  • 1970-01-01
  • 2015-07-03
  • 1970-01-01
  • 1970-01-01
  • 2018-04-23
  • 1970-01-01
  • 2015-02-20
相关资源
最近更新 更多