WPFToolkit AutoCompleteBox no se vincula correctamente dentro de ListView
Después de luchar un poco para comenzar con el control AutoCompleteBox de WPFToolkit , me enfrento a otro problema cuando intento usar un AutoCompleteBox dentro de un ListView , casi se une perfectamente, pero por una razón ignoro que no se muestra al principio ValueMemberPathy en su lugar lo intento para convertir el objeto en una cadena que da en Namespace.objectlugar del ValueMemberPathvalor adecuado , sin embargo, al seleccionar otro elemento en AutoCompleteBox, funciona perfectamente y no muestra ningún otro Namespace.object.
Aquí está mi código, puede copiarlo y pegarlo para obtener el mismo resultado (no olvide agregar DotNetProjects.WpfToolkit.Input en NuGet Package Manager) :
- Espacio de nombres.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>
- Código subyacente (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;
}
}
Respuestas
Por alguna razón, el cambio de selección que actualiza el texto de acuerdo con el ValueMemberPathno se activa al anidar el AutoCompleteBoxen ListView. El SelectionChangedevento ni siquiera dispara. No pude entender por qué exactamente y si esto es un error o no. Sin embargo, puedo mostrarte una solución con el Microsoft.Xaml.Behaviors.Wpfpaquete.
Puede crear una acción de activación que restablezca el SelectedItemy lo asigne nuevamente 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);
}
}
Esta acción de activación se puede utilizar para el Loadedevento de AutoCompleteBox.
<toolkit:AutoCompleteBox ...>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Loaded">
<local:ForceUpdateSelectedItemAction/>
</b:EventTrigger>
</b:Interaction.Triggers>
</toolkit:AutoCompleteBox>
Esto provocará una actualización de la selección y el texto sin cambiar la propiedad enlazada.