WPFToolkit AutoCompleteBox无法正确绑定到ListView中 [英] WPFToolkit AutoCompleteBox not binding correctly inside ListView

查看:67
本文介绍了WPFToolkit AutoCompleteBox无法正确绑定到ListView中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


这是我的代码,您可以复制并粘贴以获得相同的结果(不要忘记添加 DotNetProjects.WpfToolkit.Input 在NuGet软件包管理器中)



  • Namespace.MainWindow.xaml


 < Window x:Class ="命名空间。 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 = ListView中的AutoCompleteBox;高度= 300。宽度= 350 WindowStartupLocation = CenterScreen

< ;!-必需的模板,以显示ItemsList中的项目名称->
< Window.Resources>
< DataTemplate x:Key =" AutoCompleteBoxItemTemplate>>
< StackPanel Orientation = Horizo​​ntal Horizo​​ntalAlignment =中心。背景=透明
< Label Content =< {绑定名称}" />
< / StackPanel>
< / DataTemplate>
< /Window.Resources>

< StackPanel Margin = 5>
< StackPanel Orientation = Horizo​​ntal保证金= 0 5 0 0。
< StackPanel Width =" {Binding ElementName = FirstColumnWidth,Path = ActualWidth}"
< TextBlock Text = ACB绑定到Cart.Item //

< ;!-正确绑定的ACB->
< toolkit:AutoCompleteBox
ItemsSource = {Binding Path = ItemsList}
ValueMemberPath ="名称"
SelectedItem = {Binding Path = Cart.Item,Mode = TwoWay}
ItemTemplate = {StaticResource AutoCompleteBoxItemTemplate} //>
< / StackPanel>

< StackPanel Margin =" 15 0 0 0">
< TextBlock Text = Cart.Item.Name的值 //
< TextBlock Text =" {Binding Path = Cart.Item.Name}" />
< / StackPanel>
< / StackPanel>

< TextBlock Margin =" 0 30 0 0" Horizo​​ntalAlignment =中心。 Text =具有CartsList作为ItemsListSource的ListView />
< ListView ItemsSource =" {Binding CartsList}">
< ListView.View>
< GridView>
< GridViewColumn x:Name =" FirstColumnWidth">
< GridViewColumn.Header>
< TextBlock Text =绑定到每个Cart.Item的ACB /
< /GridViewColumn.Header>
< GridViewColumn.CellTemplate>
< DataTemplate>
<!-无法正确绑定的ACB->
< toolkit:AutoCompleteBox
ItemsSource = {
绑定RelativeSource = {RelativeSource AncestorType = Window},
Path = DataContext.ItemsList}
ValueMemberPath ="名称"
SelectedItem = {Binding Path = Item,Mode = TwoWay}
ItemTemplate = {StaticResource AutoCompleteBoxItemTemplate} //
< / DataTemplate>
< /GridViewColumn.CellTemplate>
< / GridViewColumn>

< GridViewColumn>
< GridViewColumn.Header>
< TextBlock Text =每个Cart.Item.Name的值 //
< /GridViewColumn.Header>
< GridViewColumn.CellTemplate>
< DataTemplate>
< TextBlock Text =" {Binding Path = Item.Name}" />
< / DataTemplate>
< /GridViewColumn.CellTemplate>
< / GridViewColumn>
< / GridView>
< /ListView.View>
< / ListView>
< / StackPanel>
< / Window>



  • 代码隐藏(MainWindow.xaml.cs)


 使用System.Collections.ObjectModel; 
使用System.ComponentModel;
使用System.Runtime.CompilerServices;
使用System.Windows;

命名空间
{
公共局部类MainWindow:Window,INotifyPropertyChanged
{
// INPC实现
公共事件PropertyChangedEventHandler PropertyChanged;
私有无效OnPropertyChanged([CallerMemberName]字符串propertyName = null)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
}

//包含将在购物车中选择的项目的列表
private ObservableCollection< Item> _ItemsList;
public ObservableCollection< Item> ItemsList
{
get => _ItemsList;
set
{
_ItemsList =值;
OnPropertyChanged();
}
}

//包含将在ListView中显示的购物车的列表
private ObservableCollection< Cart> _CartsList;
公共ObservableCollection< Cart> CartsList
{
get => _CartsList;
set
{
_CartsList =值;
OnPropertyChanged();
}
}

//标志车
私人推车_Cart;
公共购物车购物车
{
get => _大车;
set
{
_Cart =值;
OnPropertyChanged();
}
}

public MainWindow()
{
DataContext = this;
InitializeComponent();

//填充ItemsList
ItemsList = new ObservableCollection< Item>()
{
new Item( T恤),new Item(牛仔裤),新商品(靴子),
};

//填充CartsList
CartsList = new ObservableCollection< Cart>()
{
new Cart(ItemsList [0]),
new Cart( ItemsList [2]),
新购物车(ItemsList [1]),
新购物车(ItemsList [0]),
新购物车(ItemsList [1]),
} ;

//将商品设置为购物车
购物车=新购物车(ItemsList [2]);

}
}

//购物车对象
公共类购物车
{
public Item Item {get;组; }

公共购物车(物品)=>项目=项目;
}

//项目对象
公共类Item
{
//重要的是要设置为私有,因此不能更改
public字符串名称{get;私人套装; }

public Item(字符串名称)=>名称=名称;
}
}


解决方案

出于某些原因,在<$中嵌套 AutoCompleteBox 时,不会触发根据 ValueMemberPath 更新文本的选择更改。 c $ c> ListView 。 SelectionChanged 事件甚至不会触发。我不能弄清楚为什么会这样,如果这是个错误还是不是。但是,我可以使用 Microsoft.Xaml.Behaviors.Wpf 包。


您可以创建触发操作,以重置 SelectedItem ,然后在 AutoCompleteBox 上再次分配它。

 公共类ForceUpdateSelectedItemAction:TriggerAction< AutoCompleteBox> 
{
受保护的重写void调用(对象参数)
{
var selectedItem = AssociatedObject.SelectedItem;
AssociatedObject.SetCurrentValue(AutoCompleteBox.SelectedItemProperty,null);
AssociatedObject.SetCurrentValue(AutoCompleteBox.SelectedItemProperty,selectedItem);
}
}

此触发操作可用于 Loaded AutoCompleteBox 事件。

 < toolkit:AutoCompleteBox ...> 
< b:Interaction.Triggers>
< b:EventTrigger EventName =已加载>
< local:ForceUpdateSelectedItemAction />
< / b:EventTrigger>
< / b:Interaction.Triggers>
< / toolkit:AutoCompleteBox>

这将导致选择内容和文本的更新,而不会更改绑定属性。


After struggling a bit to just get started with WPFToolkit's AutoCompleteBox control, I'm facing another issue when trying to use an AutoCompleteBox inside a ListView, it almost binds perfectly but for a reason I ignore it doesn't show at first the ValueMemberPath and instead tries to convert the object to string which gives Namespace.object instead of the proper ValueMemberPath value, however when selecting another item in the AutoCompleteBox it works perfectly and it doesn't show any other Namespace.object.

Here's my code, you can just copy and paste it to get the same result (don't forget to add DotNetProjects.WpfToolkit.Input in NuGet Package Manager) :

  • 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;
    }
}

解决方案

For some reason the selection change that updates the text according to the ValueMemberPath is not triggered when nesting the AutoCompleteBox in the ListView. The SelectionChanged event does not even fire. I could not figure out why exactly and if this is a bug or not. However, I can show you a workaround using the Microsoft.Xaml.Behaviors.Wpf package.

You can create a trigger action that resets the SelectedItem and assigns it again on 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);
   }
}

This trigger action can be used for the Loaded event of the AutoCompleteBox.

<toolkit:AutoCompleteBox ...>
   <b:Interaction.Triggers>
      <b:EventTrigger EventName="Loaded">
         <local:ForceUpdateSelectedItemAction/>
      </b:EventTrigger>
   </b:Interaction.Triggers>
</toolkit:AutoCompleteBox>

This will cause an update of the selection and the text without changing the bound property.

这篇关于WPFToolkit AutoCompleteBox无法正确绑定到ListView中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆