WPFToolkit AutoCompleteBox bindet in ListView nicht richtig
Nachdem ich mich ein wenig bemüht habe, mit dem AutoCompleteBox-Steuerelement von WPFToolkit zu beginnen , habe ich ein anderes Problem, wenn ich versuche, eine AutoCompleteBox in einer ListView zu verwenden . Sie bindet fast perfekt, aber aus einem Grund, den ich ignoriere, wird sie zunächst nicht angezeigtValueMemberPath und versucht es stattdessen Um das Objekt in eine Zeichenfolge zu konvertieren, die Namespace.objectanstelle des richtigen ValueMemberPathWerts angegeben wird, funktioniert es jedoch bei Auswahl eines anderen Elements in der AutoCompleteBox einwandfrei und zeigt kein anderes an Namespace.object.
Hier ist mein Code. Sie können ihn einfach kopieren und einfügen, um das gleiche Ergebnis zu DotNetProjects.WpfToolkit.Input erzielen (vergessen Sie nicht, ihn in NuGet Package Manager hinzuzufügen ) :
- Namespace.MainWindow.xaml
<Window x:Class="Namespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Namespace"
mc:Ignorable="d"
xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=DotNetProjects.Input.Toolkit"
Title="AutoCompleteBox in ListView" Height="300" Width="350" WindowStartupLocation="CenterScreen">
<!-- 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 Margin="5">
<StackPanel Orientation="Horizontal" Margin="0 5 0 0">
<StackPanel Width="{Binding ElementName=FirstColumnWidth, Path=ActualWidth}">
<TextBlock Text="ACB binded to Cart.Item"/>
<!-- ACB that binds correctly -->
<toolkit:AutoCompleteBox
ItemsSource="{Binding Path=ItemsList}"
ValueMemberPath="Name"
SelectedItem="{Binding Path=Cart.Item, Mode=TwoWay}"
ItemTemplate="{StaticResource AutoCompleteBoxItemTemplate}"/>
</StackPanel>
<StackPanel Margin="15 0 0 0">
<TextBlock Text="Value of Cart.Item.Name"/>
<TextBlock Text="{Binding Path=Cart.Item.Name}"/>
</StackPanel>
</StackPanel>
<TextBlock Margin="0 30 0 0" HorizontalAlignment="Center" Text="ListView with CartsList as ItemsListSource"/>
<ListView ItemsSource="{Binding CartsList}">
<ListView.View>
<GridView>
<GridViewColumn x:Name="FirstColumnWidth">
<GridViewColumn.Header>
<TextBlock Text="ACB binded to each Cart.Item"/>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<!-- ACB that doesn't bind correctly -->
<toolkit:AutoCompleteBox
ItemsSource="{
Binding RelativeSource={RelativeSource AncestorType=Window},
Path=DataContext.ItemsList}"
ValueMemberPath="Name"
SelectedItem="{Binding Path=Item, Mode=TwoWay}"
ItemTemplate="{StaticResource AutoCompleteBoxItemTemplate}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn >
<GridViewColumn.Header>
<TextBlock Text="Value of each Cart.Item.Name"/>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Item.Name}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Window>
- Code-Behind (MainWindow.xaml.cs)
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace Namespace
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
// INPC Implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
// The list that contains Items that will be chosen in a Cart
private ObservableCollection<Item> _ItemsList;
public ObservableCollection<Item> ItemsList
{
get => _ItemsList;
set
{
_ItemsList = value;
OnPropertyChanged();
}
}
// The list that contains Carts that will be shown in the ListView
private ObservableCollection<Cart> _CartsList;
public ObservableCollection<Cart> CartsList
{
get => _CartsList;
set
{
_CartsList = value;
OnPropertyChanged();
}
}
// A signle Cart
private Cart _Cart;
public Cart Cart
{
get => _Cart;
set
{
_Cart = value;
OnPropertyChanged();
}
}
public MainWindow()
{
DataContext = this;
InitializeComponent();
// Populating ItemsList
ItemsList = new ObservableCollection<Item>()
{
new Item("T-shirt"), new Item("Jeans"), new Item("Boots"),
};
// Populating CartsList
CartsList = new ObservableCollection<Cart>()
{
new Cart(ItemsList[0]),
new Cart(ItemsList[2]),
new Cart(ItemsList[1]),
new Cart(ItemsList[0]),
new Cart(ItemsList[1]),
};
// Setting an Item to Cart
Cart = new Cart(ItemsList[2]);
}
}
// Cart Object
public class Cart
{
public Item Item { get; set; }
public Cart(Item item) => Item = item;
}
// Item Object
public class Item
{
// Important to be private set so it cannot be changed
public string Name { get; private set; }
public Item(string name) => Name = name;
}
}
Antworten
Aus irgendeinem Grund wird die Auswahländerung, die den Text entsprechend aktualisiert, ValueMemberPathbeim Verschachteln der AutoCompleteBoxin nicht ausgelöst ListView. Die SelectionChangedVeranstaltung wird nicht einmal ausgelöst. Ich konnte nicht genau herausfinden, warum und ob dies ein Fehler ist oder nicht. Ich kann Ihnen jedoch eine Problemumgehung mit dem Microsoft.Xaml.Behaviors.WpfPaket zeigen.
Sie können eine Triggeraktion erstellen, die das zurücksetzt SelectedItemund es erneut zuweist AutoCompleteBox.
public class ForceUpdateSelectedItemAction : TriggerAction<AutoCompleteBox>
{
protected override void Invoke(object parameter)
{
var selectedItem = AssociatedObject.SelectedItem;
AssociatedObject.SetCurrentValue(AutoCompleteBox.SelectedItemProperty, null);
AssociatedObject.SetCurrentValue(AutoCompleteBox.SelectedItemProperty, selectedItem);
}
}
Diese Triggeraktion kann für das LoadedEreignis des verwendet werden AutoCompleteBox.
<toolkit:AutoCompleteBox ...>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Loaded">
<local:ForceUpdateSelectedItemAction/>
</b:EventTrigger>
</b:Interaction.Triggers>
</toolkit:AutoCompleteBox>
Dies führt zu einer Aktualisierung der Auswahl und des Textes, ohne die gebundene Eigenschaft zu ändern.