确切的问题是 - 为什么使用Convert而不是ConvertBack,为什么首先需要ConvertBack呢?
下面是我的问题的例子,我试图简化一些事情。这是普通的WPF,没有第三方库,问题本身就是经典的主要细节,有点麻烦。
我有listbox(城市列表)和datagrid(列出我所有的朋友+电话)。当我选择列表框时,datagrid应刷新并显示所选城市的人员。 datagrid如下所示:
Name | Phone | PhoneType
Mark | 76447 | cellphone
...
这里的关键问题是PhoneType列。每个单元格应该是一个填充预定义手机类型的组合框(从数据库中获取)。而扭曲在于db结构。它是这样的:
typeID | PhoneType | PhoneDescription
1 | cellphone | NULL
2 | neighbour | call only in case of emergency
在我的数据网格组合框中,如果存在PhoneDescription,则应显示但 PhoneType,应使用它而不是普通的PhoneType。
问题的结束。你和我在一起?
为了在datagrid中使用combobox,我必须使用带有combobox的模板列,而不是使用combobox datagrid列(这就是为什么: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'。
有了这个,我不知道发生了什么。为什么字符串传递给Convert ???它看起来更像ConvertBack。
答案 0 :(得分:1)
我认为在这种情况下,使用PriorityBinding会更容易。它将处理描述为null的情况,并为您使用类型:
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<PriorityBinding>
<Binding Path="PhoneDescription" />
<Binding Path="PhoneType" />
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
答案 1 :(得分:0)
正如我所看到的,textblock绑定到PhoneTypesList返回的内容。然后就是使用转换器,它需要一个PhoneTypeRecord。 我想PhoneTypesList是PhoneTypeRecord的列表吗? 我注意到的是,在转换器中,我得到的完整列表并不是列表中的每个元素。所以你实际上得到了PhoneTypeRecord的list / collection / observableCollection。验证它。
您还可以在转换器中添加这样的条件:
if(value != typeof(what_you_are_expecting) throw new InvalidOperationException("something is wrong");