Преобразование ComboBox в AutoCompleteBox с помощью WPF Toolkit

Aug 17 2020

У меня проблемы с преобразованием "сложного" ComboBox в столь же сложный AutoCompleteBox. Моя цель - иметь возможность выбирать и настраивать элемент ShoppingCart как один из элементов списка. Вот три шага, которые нужно предпринять, чтобы воспроизвести мою ситуацию (я использую Stylet и его метод SetAndNotify () INPC) :

  1. Создайте два объекта, один из которых имеет только свойство Name, а другой - только другой объект в качестве свойства.

    public class ItemModel : PropertyChangedBase
    {
        private string _name;
        public string Name
        {
            get => _name;
            set => SetAndNotify(ref _name, value);
        }
    }
    
    public class ShoppingCartModel : PropertyChangedBase
    {
        public ItemModel Item { get; set; }
    }
    
  2. инициализировать и заполнить как ItemsList, так и Shoppingcart в DataContext (поскольку мы используем MVVM, это ViewModel)

    public ShoppingCartModel ShoppingCart { get; set; }
    public ObservableCollection<ItemModel> ItemsList { get; set; }
    
    public ShellViewModel()
    {
        ItemsList = new ObservableCollection<ItemModel>()
        {
            new ItemModel { Name = "T-shirt"},
            new ItemModel { Name = "Jean"},
            new ItemModel { Name = "Boots"},
            new ItemModel { Name = "Hat"},
            new ItemModel { Name = "Jacket"},
        };
    
        ShoppingCart = new ShoppingCartModel() { Item = new ItemModel() };
    }
    
  3. Создайте AutoCompleteBox, ComboBox и небольшой TextBlock внутри View, чтобы проверить все это:

    <Window [...] xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=DotNetProjects.Input.Toolkit">
    
        <!-- Required Template to show the names of the Items in the ItemsList -->
        <Window.Resources>
            <DataTemplate x:Key="AutoCompleteBoxItemTemplate">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Background="Transparent">
                    <Label Content="{Binding Name}"/>
                </StackPanel>
            </DataTemplate>
        </Window.Resources>
    
        <StackPanel>
            <!-- AutoCompleteBox: can see the items list but selecting doesn't change ShoppingCart.Item.Name -->
            <Label Content="AutoCompleteBox with ShoppingCart.Item.Name as SelectedItem:"/>
            <toolkit:AutoCompleteBox ItemsSource="{Binding ItemsList}"
                                     ValueMemberPath="Name"
                                     SelectedItem="{Binding Path=ShoppingCart.Item.Name}" 
                                     ItemTemplate="{StaticResource AutoCompleteBoxItemTemplate}"/>
    
            <!-- ComboBox: can see the items list and selecting changes ShoppingCart.Item.Name value -->
            <Label Content="ComboBox with ShoppingCart.Item.Name as SelectedValue:"/>
            <ComboBox ItemsSource="{Binding ItemsList}" 
                      DisplayMemberPath="Name"
                      SelectedValue="{Binding Path=ShoppingCart.Item.Name}"
                      SelectedValuePath="Name"
                      SelectedIndex="{Binding Path=ShoppingCart.Item}" />
    
            <!-- TextBox: Typing "Jean" or "Jacket" updates the ComboBox, but not the AutoCompleteBox -->
            <Label Content="Value of ShoppingCart.Item.Name:"/>
            <TextBox Text="{Binding Path=ShoppingCart.Item.Name}"/>
        </StackPanel>
    </window>
    

Изменение режима привязки SelectedItem AutoCompleteBox на TwoWay заставляет его печатать « [ProjectName] .ItemModel », что означает (я полагаю?), Он получает ItemModels, а не строки, но я не могу заставить его работать. Мы будем благодарны за любую помощь, спасибо и не стесняйтесь редактировать мой пост, если можно сделать его меньше.

Ответы

Saliom Aug 21 2020 at 21:07

После долгих попыток я наконец нашел виновных:

  • INPC не реализован, ShoppingCartModel.Itemнесмотря на PropertyChangedBaseнаследование (либо реализация INPC, либо удаление PropertyChangedBaseработы наследования)

    public class ShoppingCartModel : PropertyChangedBase
    {
        private ItemModel _item;
        public ItemModel Item
        {
            get => _item;
            set => SetAndNotify(ref _item, value);
        }
    }
    
  • AutoCompleteBox SelectedItemдолжен быть того же типа ItemsSourceи иметь TwoWayрежимBinding

    <toolkit:AutoCompleteBox ItemsSource="{Binding ItemsList}"
                             ValueMemberPath="Name"
                             SelectedItem="{Binding Path=ShoppingCart.Item, Mode=TwoWay}" 
                             ItemTemplate="{StaticResource AutoCompleteBoxItemTemplate}"/>
    
  • И наконец ... самый загадочный - ComboBox! Просто находясь там, он портит, AutoCompleteBoxи я понятия не имею, почему, просто комментируя весь ComboBox, все это работает. Если вы знаете, почему ComboBox нарушает привязку AutoCompleteBox, не стесняйтесь помочь.

Однако есть еще одна проблема при использовании AutoCompleteBox внутри ListView, но лучше создать отдельный вопрос для этой проблемы здесь