为什么在此 MultiBinding 上未调用 ConvertBack?

发布于 2024-11-17 16:55:09 字数 4731 浏览 2 评论 0原文

我的组合框列表“联系人”使用 MultiBinding 绑定到 FullName 和 PhoneExtension。 IMul​​tiValueConverter 的 Convert 方法被调用,但 ConvertBack 未被调用。为什么? 组合框正确显示列表,但未保存选择。当我按 Tab 键离开时,它会消失。

背景:

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) 组合框位于用户控件上的数据网格中。这就是这种古怪绑定的原因: ItemsSource="{Binding ContactListObservable,relativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"

3) IMultiValueConverter 是 UserControl.Resources 中引用为 的类<本地:CombineNameAndPhoneExtensionMultiConverter x:Key="combinedNameAndPhoneExtensionConverter"/>

4) 在联系人列表中找不到的旧数据必须显示。这是通过结合显示值的 TextBlock 和用于编辑的 ComboBox 使用 DataGridTemplateColumn 来完成的。请参阅这篇 Julie Lerman MSDN 文章

这是疯狂的 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>

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

更多背景:

包含我的组合框的数据网格每行包含一个实体框架联系人对象,并包含其他联系人字段。下面是一些有效的 XAML,它成功显示并保存 FullName,但不显示我想要与 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>

My combobox listing Contacts is bound to both FullName and PhoneExtension using MultiBinding. The Convert method of IMultiValueConverter is called but ConvertBack is not. Why? The combobox properly displays the list but the selection is not saved. It disappears when I tab away.

Background:

1) The Contact list comes from a web service and is put in an observable collection ContactListObservable in the code behind. I'm not using a 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) The combobox is in a datagrid located on a UserControl. That's the reason for this wacky binding: ItemsSource="{Binding ContactListObservable, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"

3) The IMultiValueConverter is a class referenced in UserControl.Resources as <local:CombineNameAndPhoneExtensionMultiConverter x:Key="combinedNameAndPhoneExtensionConverter"/>

4) Legacy data NOT found in the Contacts list must display. This is accomplished with a DataGridTemplateColumn by combining a TextBlock to display values and a ComboBox for editing. See this Julie Lerman MSDN article.

Here is the crazy 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>

I've devoted WAY too much time to this so I'll greatly appreciate any help you can offer.

More Background:

The datagrid containing my combobox contains one entity framework contact object per row and includes additional contact fields. Here is some working XAML that succesfully displays and saves FullName but not the phone extension which I want to save in combination with the 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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

殤城〤 2024-11-24 16:55:09

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

The TextBlock will never change it's Text property, so there is no reason to call the ConvertBack method. You would need to be bind to either the ComboBox's SelectedItem or Text properties to get updates.

烦人精 2024-11-24 16:55:09

我正在回答我自己的问题,以详细说明 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 的快速回复!

I'm answering my own question to elaborate on CodeNaked's accurate answer. Add this to the problem XAML and everything works - ConvertBack is called and both FullName and PhoneExtension are saved as needed:

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

Here is the combinedNameAndPhoneExtensionConverter code:

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;
    }

}

Thanks CodeNaked for your fast reply!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文