Conversion d'une zone de liste déroulante en une zone de saisie semi-automatique à l'aide de la boîte à outils WPF

Aug 17 2020

J'ai un peu de mal à réaliser la conversion d'une ComboBox "complexe" en une AutoCompleteBox tout aussi complexe. Mon objectif est de pouvoir sélectionner et définir l'article d'un panier d'achat comme l'un des articles d'une liste. Voici les trois étapes à suivre pour reproduire ma situation (j'utilise Stylet et sa méthode SetAndNotify () INPC) :

  1. Créez deux objets, l'un n'ayant qu'une propriété Name et l'autre n'ayant que l'autre objet comme propriété

    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. initialiser et remplir à la fois le ItemsList et le Shoppingcart dans le DataContext (puisque nous utilisons MVVM, c'est le 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. Créez l'AutoCompleteBox, ComboBox et un petit TextBlock à l'intérieur de la vue pour tout tester:

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

Changer le mode de liaison de SelectedItem de l'AutoCompleteBox en TwoWay le fait imprimer " [ProjectName] .ItemModel " ce qui signifie (je suppose?) Qu'il obtient des ItemModels et non des chaînes, mais je n'arrive pas à le faire fonctionner. Toute aide sera appréciée, merci et n'hésitez pas à modifier mon message s'il est possible de le réduire.

Réponses

Saliom Aug 21 2020 at 21:07

Après de nombreuses tentatives, j'ai finalement trouvé les coupables:

  • INPC non implémenté ShoppingCartModel.Itemmalgré l' PropertyChangedBasehéritage (implémentation d'INPC ou suppression du PropertyChangedBasetravail d'héritage)

    public class ShoppingCartModel : PropertyChangedBase
    {
        private ItemModel _item;
        public ItemModel Item
        {
            get => _item;
            set => SetAndNotify(ref _item, value);
        }
    }
    
  • Les AutoCompleteBox SelectedItemdoivent être du même type ItemsSourceet avoir un TwoWaymodeBinding

    <toolkit:AutoCompleteBox ItemsSource="{Binding ItemsList}"
                             ValueMemberPath="Name"
                             SelectedItem="{Binding Path=ShoppingCart.Item, Mode=TwoWay}" 
                             ItemTemplate="{StaticResource AutoCompleteBoxItemTemplate}"/>
    
  • Et enfin ... le plus mystérieux est le ComboBox! Simplement en étant là, ça dérange le AutoCompleteBoxet je ne sais pas pourquoi, il suffit de commenter l'ensemble de la ComboBox pour que tout fonctionne. Si vous savez pourquoi le ComboBox rompt la liaison de l'AutoCompleteBox, n'hésitez pas à vous aider.

Il y a un autre problème cependant, lors de l'utilisation d'un AutoCompleteBox dans un ListView, mais il est préférable de créer une question distincte pour ce problème ici