【问题标题】:DependencyProperty.unsetValue in a multibinding多绑定中的 DependencyProperty.unsetValue
【发布时间】:2018-11-10 13:51:41
【问题描述】:

我有一个列表视图,其中包含“书”实例的项目,当我单击一本书时,组合框应显示其关键字;实际上它有点棘手:组合框包含所有书籍的所有关键字的列表(重复删除)(组合框项是复选框),并且选中了所选书籍的关键字。 这是多重绑定:

<ComboBox
                        x:Name="cbb_Keywords"
                        Grid.Column="2"
                        Width="300"
                        Margin="5,0,0,0"
                        HorizontalAlignment="Left"
                        ItemsSource="{Binding Source={StaticResource AllBooks}}"
                        DataContext="{Binding ElementName=listBoxBooks,Path=SelectedItem,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">

                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <CheckBox Width="200">
                                        <CheckBox.IsChecked>
                                            <MultiBinding Converter="{StaticResource TextInListTrueFalseConverter}" >
                                                <Binding Path="KeywordsForTextbox"></Binding>
                                                <Binding RelativeSource="{RelativeSource Self}" Path="Content"></Binding>
                                            </MultiBinding>
                                        </CheckBox.IsChecked>
                                    </CheckBox>
                                </StackPanel>
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>

当我运行我的程序时,当我点击一本书时似乎没问题,但当我点击组合框时出现异常:不可能从“MS.Internal.NamedObject”类型转换为“System.String”类型。我看到 value[0] 是 UnsetValue。

在调试时,当我使用间谍跟踪 WpfApp1.App.Books[0].KeywordsForTextbox 的值时,它给了我很好的值(一个字符串,它是 Book[0] 的关键字列表。也许问题来自 listboxBooks.SelectedItem.KeywordsForTextBox?我无法在 VS 中窥探“listboxBooks”的值。

一些相关内容... MainWindow的构造函数的开头:

public MainWindow()
        {


            InitializeComponent();
            listBoxBooks.ItemsSource = App.Books;

转换器的convert方法:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var check = false;
            if ((values != null && values.Length == 2))
            {
                string listString = (string)values[0];
                string wordToFind = (string) values[1];
                if ((listString != null))
                {
                    List<string> keywordsList = listString.Split(',').ToList();
                    if (keywordsList.Contains(wordToFind)) check = true;
                }

            }

            return check;


        }

KeywordsForTextbox 方法:

public string KeywordsForTextbox
        {
            get { return string.Join(",", _keywords); }

        }

最后是 AllBooks 的实现:(作为窗口资源)

<ObjectDataProvider
            x:Key="AllBooks"
            MethodName="listOfAllKeywords"
            ObjectType="{x:Type mangmt:BookManagement}" />

谢谢。

【问题讨论】:

  • 首先,我假设您的 TextInListTrueFalseConverter 的 Convert 方法会引发异常。那么,是在将values[0] 转换为字符串时还是在将values[1] 转换为时发生异常?我猜是后者(值来自&lt;Binding RelativeSource="{RelativeSource Self}" Path="Content"&gt;)。我对项目对象如何与项目视觉关联的回忆有点生疏,但是如果您使用稍微不同的绑定会发生什么(参考项目视觉本身的 DataContext):&lt;Binding RelativeSource="{RelativeSource Self}" Path="DataContext"&gt;?
  • 否,value[0] 是抛出异常的那个,值是 DependencyProperty.Unset,一个占位符,表示绑定有问题。但是为什么,这是我的问题。
  • 啊,抱歉。我错过了您提到 value[0] 的句子...请注意,您的 ComboBox 项目来源是 AllBooks。现在,除了 BookManagement 类型之外,不知道 AllBooks 到底是什么(我想是一些带有某种类型条目的集合)。但是,显然,组合框项将是此 BookManagement 集合中的元素。因此 KeywordsForTextbox 绑定将尝试在 BookManagement 集合的元素中查找 KeywordsForTextbox。 (1/2)
  • 我注意到您只与App.Books 一起谈论KeywordsForTextbox,但从不与AllBooks 一起谈论。如果 KeywordsForTextbox 属性仅由 listBoxBooks.SelectedItem 中的对象提供,则不能只设置组合框的 DataContext 并完成它(因为项目模板中的绑定默认绑定相应项目视觉对象的 DataContext,它是 Combobox.ItemsSource 中的项目对象)。如果您需要项目模板绑定到相应项目对象“外部”的数据,则需要指定绑定源(2/2)

标签: c# wpf data-binding


【解决方案1】:

Multi的第一个Binding应该是Books的ListBox中的SelectedItem。我在 &lt;CheckBox.IsChecked&gt; 中添加了适当的位置,并将 Content="{Binding}" 添加到 CheckBox:

                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <CheckBox Width="200" Content={Binding}>
                              <CheckBox.IsChecked>
                                <MultiBinding Converter="{StaticResource TextInListTrueFalseConverter}" >
                                    <Binding ElementName=listBoxBooks, Path=SelectedItem.KeywordsForTextbox"></Binding>
                                    <Binding RelativeSource="{RelativeSource Self}" Path="Content"></Binding>
                                </MultiBinding>
                              </CheckBox.IsChecked>
                            </CheckBox>
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>

您可能还希望向 IMultiValueConverter 添加一些验证,以确保未设置传递的值,以避免出现异常:VB 中的If Not values(0) Is DependencyProperty.UnsetValue And Not values(1) Is DependencyProperty.UnsetValue Then

关于选中复选框的行为,我猜这是因为 IMultiValueConverter 的 ConvertBack 方法。您可以删除“抛出异常”代码,并编写一个方法来将选中/未选中框的文本添加/删除到您的关键字列表中。

【讨论】:

  • 我尝试了另一种选择,可能更糟:stackoverflow.com/questions/53265084/…。你觉得可以直接从convertBack方法修改listview的selectedItem吗?
  • 抱歉耽搁了 - 看到您的答案似乎对您有用,但是是的,我认为您可以使用 ConvertBack 函数将 CheckBox 内容添加到您的单词列表中。我只是检查列表以查看该单词是否已包含在内。如果用空字符串替换,如果不是,则添加它。只要 List 属性实现 INotifyPropertyChanged,那么您的文本框也应该更新。您甚至可以考虑将关键字列表设置为可观察的集合而不是字符串 - 您所做的大部分操作都是列表操作,只需转换为 TextBox 的字符串
猜你喜欢
  • 1970-01-01
  • 2020-10-06
  • 2016-05-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 2011-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多