привязать ComboboxItem как флажок к его присутствию в списке? - PullRequest
0 голосов
/ 09 ноября 2018

Я новичок в wpf, и, кроме прочтения «WPF unleashed», я пытаюсь написать небольшую программу, которая дает мне направление, по которому можно идти. Итак, вот моя проблема: я хочу управлять своими книгами дома с помощью небольшой библиотечной программы. Каждая книга хранится в экземпляре класса Book. таким образом, класс This Book содержит всю информацию о книге, а также ее ключевые слова, которые представляют собой ObservableCollection в свойстве «Keywords»:

public ObservableCollection<string> Keywords
        {
            get => _keywords;
            set
            {
                _keywords = value;
                OnPropertyChanged("Keywords");
            }
        }

(_ ключевые слова - строка).

Мне нужно отобразить текстовое поле и поле со списком, которые показывают связанную часть информации: поле текста показывает все ключевые слова выбранной книги, а поле со списком показывает список флажков, он заполняется списком всех Ключевые слова во всех книгах библиотеки указаны один раз (дубликаты удалены), и каждый флажок отмечен, если ключевое слово присутствует в списке выбранной книги. Я попытаюсь объяснить это по-разному: каждая книга содержит список всех своих ключевых слов. В комбинированном ящике содержатся все существующие ключевые слова (из всех книг), и те, которые относятся к выбранной книге, отмечены: это позволяет мне добавлять / редактировать / удалять ключевые слова двумя способами: с помощью текстового поля или установкой / снятием флажка.

Возвращаясь к моей проблеме: как я могу закодировать это, используя максимум привязки данных? Для текстового поля я не вижу проблем: я создам свойство в «Книге», скажем «KeywordsForTextbox», с использованием только метода получения, возвращающего элементы коллекции ключевых слов, объединенные с соответствующим разделительным символом. затем, используя dataContext, указывающий на выбранную книгу, свойство text текстового поля привязывается к KeywordsForTextbox. Я бы предпочел не рассматривать издание текстового поля на данный момент.

Но для комбинированного списка есть две вещи, которые нужно связать: 1 / список всех ключевых слов. Я могу добавить в свой класс BookManagement (который ... управляет классом Book) свойство, получатель которого вернет список всех ключевых слов (по ссылке). 2 / каждый ComboboxItem будет редактироваться в XAML, но как реализовать поведение установки его как отмеченного / непроверенного, если заданное ключевое слово (полученное с помощью свойства ItemSource флажка для свойства Keyword экземпляра Book) содержится в selectedItem Ключевые слова?

короче: как связать свойство selected объекта CheckBoxItem с наличием этой строки в selectedItem.Keywords (список строк) списка ListView?

Я прошу прощения за грязный аспект моего вопроса!

спасибо.

EDIT

Ну, мне удалось написать все, он собирает и запускает, но есть проблема; фактически в выпадающем списке, itemsSource был записан так:

ItemsSource="{Binding Source={StaticResource AllBooks}}"

и AllBooks - это ресурс:

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

вот метод:

public static ObservableCollection<string> listOfAllKeywords()
        {
            if (App.Books != null)
            {

                IEnumerable<string> kws = App.Books.SelectMany(book => book.Keywords).Distinct();
                return new ObservableCollection<string>(kws);

            }
            else return new ObservableCollection<string>();


        }

Когда я запускаю свою программу, окно отображается нормально, но если я нажимаю на книгу, чтобы отобразить ее, и если я нажимаю на поле со списком, при втором щелчке я получаю исключение: System.InvalidCastException: «Невозможно повлиять на объект типа« MS.Internal.NamedObject ». Тип« System.String ». что поговорка невозможна. В отладке я увидел, что в мультибиндинге параметр secondf имеет значение null (в любом случае он кажется не очень актуальным, поскольку исключение вызвано первым параметром, но все же это раздражает).

Я вспоминаю вам мой мультисвязь:

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

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

вот ключевые слова для текстового поля:

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

        }

(это в классе Книги) первое связывание (мультисвязывания) неверно? почему?

спасибо.

РЕДАКТИРОВАТЬ 2 Я создал новое сообщение, потому что оно слишком грязное (слишком много текста в моем вопросе), а область возможных причин сильно ограничена, так как я обнаружил, что это проблема dependencyProperty. вот ссылка: здесь в переполнении стека

1 Ответ

0 голосов
/ 10 ноября 2018

на основании моего предложения в комментарии IMultiValueConverter (извините в VB):

Public Class TextInListTrueFalseConverter
    Implements IMultiValueConverter

    Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IMultiValueConverter.Convert
        Dim Checked As Boolean = False
        If Not values Is Nothing Then
            If values.Count = 2 Then
                Dim ListString As String = values(0)
                Dim WordToFind As String = values(1)
                If Not ListString Is Nothing Then
                    Dim KeywordList As List(Of String) = ListString.Split(";").ToList 'Assuming you seperator is a ;
                    If KeywordList.Contains(WordToFind) Then Checked = True
                End If
            End If
        End If
        Return Checked
    End Function

    Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function
End Class

XAML:

<CheckBox >
    <CheckBox.IsChecked>
        <MultiBinding Converter="{StaticResource TextInListTrueFalseConverter}">
             <Binding Path="KeywordsForTextbox" />
             <Binding RelativeSource="{RelativeSource Self}" Path="Content" />
        </MultiBinding>
    </CheckBox.IsChecked>
</CheckBox>

(используйте DataContext из Combo для привязки к классу Bookи используйте ItemsSource для загрузки KeyWords)

Наконец, добавьте <Local:TextInListTrueFalseConverter x:Key="TextInListTrueFalseConverter" /> в качестве ресурса, добавив "Локальное" пространство имен, если его еще нет. Например: xmlns:Local="clr-namespace:APPNAME".

Не проверено,но думаю, что это должно сработать, или, по крайней мере, дать вам кое-что для продолжения.

РЕДАКТИРОВАТЬ

Мой плохой.У меня было в голове, что ComboBoxItems будет наследовать DataContext из ComboBox, но, конечно, нет - они, очевидно, связаны с ItemsSource.Попробуйте следующие изменения, я обновил первую привязку к списку книг.Я также добавил в <CheckBox.IsChecked>, где это уместно, а также добавил 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, чтобы убедиться, что переданные значения не являютсяunset, чтобы избежать исключения: If Not values(0) Is DependencyProperty.UnsetValue And Not values(1) Is DependencyProperty.UnsetValue Then в VB.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...