【问题标题】:Why is ConvertBack not called on this MultiBinding?为什么没有在这个 MultiBinding 上调用 ConvertBack?
【发布时间】:2011-09-24 12:23:09
【问题描述】:

我的组合框列表联系人使用 MultiBinding 绑定到 FullName 和 PhoneExtension。调用 IMultiValueConverter 的 Convert 方法,但未调用 ConvertBack。为什么? 组合框正确显示列表,但未保存选择。当我离开时它消失了。

背景:

1) 联系人列表来自一个 Web 服务,并在后面的代码中放入一个可观察的集合 ContactListObservable。我没有使用 ViewModel。

PhoneBookService phoneBookService = new PhoneBookService();
PhoneRecordArray pbs = GetCompletePhoneListing();
List<PhoneRecord> pbsList = pbs.PhoneArray.ToList();

ObservableCollection<Contact> observableContacts = new ObservableCollection<Contact>();

foreach(PhoneBookService.PhoneRecord rec in pbsList)
{
  Contact c = new Contact();
  c.FullName = rec.Person;
  c.PhoneExtension = rec.Phone;
  observableContacts.Add(c);
}

ContactListObservable = observableContacts;

2) 组合框位于 UserControl 上的数据网格中。这就是这种古怪绑定的原因:ItemsSource="{Binding ContactListObservable, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"

3) IMultiValueConverter 是在 UserControl.Resources 中引用为 &lt;local:CombineNameAndPhoneExtensionMultiConverter x:Key="combinedNameAndPhoneExtensionConverter"/&gt; 的类

4) 必须显示联系人列表中未找到的旧数据。这是通过一个 DataGridTemplateColumn 完成的,它结合了一个 TextBlock 来显示值和一个 ComboBox 来进行编辑。见this Julie Lerman MSDN article

这是疯狂的 XAML:

<DataGridTemplateColumn x:Name="DataGridContactTemplateColumn" Header="Contact Using Template">
<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <TextBlock>
            <TextBlock.Text>
                <MultiBinding  StringFormat="{}{0} Ext. {1}">
                        <Binding Path="FullName"/>
                        <Binding Path="PhoneExtension"/>
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate x:Name="ContactsCellEditingTemplate">
        <Grid FocusManager.FocusedElement="{Binding ElementName=ContactsTemplateComboBox}">
            <ComboBox x:Name="ContactsTemplateComboBox" IsSynchronizedWithCurrentItem="False" IsEditable="False" IsDropDownOpen="True" ItemsSource="{Binding ContactListObservable, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock DataContext="{Binding}">
                            <TextBlock.Text>                                                        
                                <MultiBinding  Converter="{StaticResource combinedNameAndPhoneExtensionConverter}">                             
                                    <Binding Path="FullName" UpdateSourceTrigger="PropertyChanged"/>                              
                                    <Binding Path="PhoneExtension" UpdateSourceTrigger="PropertyChanged"/>
                                </MultiBinding>
                            </TextBlock.Text>
                        </TextBlock>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
        </Grid>
    </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

我为此投入了太多时间,因此我将非常感谢您提供的任何帮助。

更多背景:

包含我的组合框的数据网格每行包含一个实体框架联系人对象,并包含其他联系人字段。这是成功显示并保存 FullName 的一些工作 XAML,但不是我想与 FullName 一起保存的电话分机:

<DataGridTemplateColumn x:Name="DataGridContactTemplateColumn" Header="Contact Using Template">
  <DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding Path=FullName}"/>
    </DataTemplate>
  </DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate x:Name="ContactsCellEditingTemplate">
        <Grid FocusManager.FocusedElement="{Binding ElementName=ContactsTemplateComboBox}">
            <ComboBox x:Name="ContactsTemplateComboBox" ItemsSource="{Binding ContactListObservable, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" DisplayMemberPath="FullName" SelectedValuePath="FullName" Text="{Binding Path=FullName}" SelectedItem="{Binding Path=FullName}" IsSynchronizedWithCurrentItem="False" IsEditable="False" IsDropDownOpen="True"/>
        </Grid>
    </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

【问题讨论】:

    标签: wpf xaml binding multibinding


    【解决方案1】:

    TextBlock 永远不会改变它的 Text 属性,因此没有理由调用 ConvertBack 方法。您需要绑定到 ComboBox 的 SelectedItem 或 Text 属性才能获取更新。

    【讨论】:

    • 你能详细说明一下吗?如何通过绑定到 SelectedItem 或 Text 来显示组合框列表并保存 FullName 和 PhoneExtension?一些示例代码可以帮助我理解。谢谢。
    • @DeveloperDan - ComboBox 有两个方面。首先是供选择的项目(看起来您已经正确设置了此设置),然后是选择本身。选择由 SelectedItem 属性指示,但 Text 属性也可以具有用户的输入(如果 IsEditable 为 true)。您的示例并未指示 DataGrid 显示的数据,因此除了basic examples 之外很难想出任何东西。如果您可以提供更多详细信息,我可以详细说明我的答案。
    • 我为我的问题添加了更多背景信息。网格显示保存到名为 Contact 的实体框架实体的多个联系人字段。当组合框文本简单地绑定到 FullName 时,一切正常。当我尝试使用多重绑定以使每个 FullName 都有一个关联的 PhoneExtension 时,就会出现问题。
    【解决方案2】:

    我正在回答我自己的问题,以详细说明 CodeNaked 的准确答案。 将此添加到问题 XAML 中,一切正常 - 调用 ConvertBack 并根据需要保存 FullName 和 PhoneExtension:

    <ComboBox.SelectedItem>
        <MultiBinding Converter="{StaticResource combinedNameAndPhoneExtensionConverter}">
            <Binding Path="FullName" UpdateSourceTrigger="PropertyChanged"/>
            <Binding Path="PhoneExtension" UpdateSourceTrigger="PropertyChanged"/>
        </MultiBinding>
    </ComboBox.SelectedItem>
    

    这里是组合的NameAndPhoneExtensionConverter 代码:

    public class CombineNameAndPhoneExtensionMultiConverter : IMultiValueConverter
    {
        public object Convert(object[] values,
                              Type targetType,
                              object parameter,
                              System.Globalization.CultureInfo culture)
        {
            if (values[0] as string != null)
            {
                string fullName = (string)values[0];
                string phoneExtension = (string)values[1];
                string namePlusExtension = fullName + ", " + phoneExtension;
                return namePlusExtension;
            }
            return null;
        }
    
        public object[] ConvertBack(object value,
                                    Type[] targetTypes,
                                    object parameter,
                                    System.Globalization.CultureInfo culture)
        {
            Contact c = (Contact)value;
    
            string[] returnValues = { c.FullName, c.PhoneExtension };
            return returnValues;
        }
    
    }
    

    感谢 CodeNaked 的快速回复!

    【讨论】:

      猜你喜欢
      • 2012-11-15
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 2020-11-21
      • 2019-06-28
      • 2017-05-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多