Combobox数据绑定与项目模板

时间:2014-02-01 01:14:27

标签: wpf combobox

我正在尝试创建一个包含World of warcraft项目列表的wpf组合框。我正在使用组合框的项目模板,以便项目图标和项目名称显示在组合框下拉列表中。它按原样工作,我可以开始输入项目名称,弹出窗口中的项目列表会自动过滤。

问题是当我点击一个项目时,我希望项目名称显示在组合框文本区域中。相反,我得到的是一个非常简短的ItemDisplayModel.ToString(),然后是一个空字符串。

ItemDisplayModel.ToString()是我从列表中选择的ItemDisplayModel类型。这有意义导致组合框控件ItemsSource属性包含ItemDisplayModel类型的数组。

但在我的AuctionHouseFilterItemNameModel.Value属性中,我检测到天气值已更改,如果是,则重建要在组合框中显示的项目列表。因为当我单击弹出列表中的项目时,组合框中的文本被更改为ItemDisplayModel.ToString(),它再次重建项目列表,这次没有匹配,因为ItemDisplayModel.ToString()与任何已知项目都不匹配名。

我想要做的就是当我单击弹出列表中的项目时,我希望将ItemDisplayModel.Name映射到AuctionHouseFilterItemNameModel.Value属性,并让组合框文本区域显示AuctionHouseFilterItemNameModel.Value。

这有意义吗?我尝试了很多不同的方式而且我很茫然。环顾网络也没有给我答案。我确信这个问题很容易解决,但解决办法使我无法解决。

这是我的XAML控件

<UserControl
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:AuctionHouseSearchFilters="clr-namespace:Codefarts.WowTracks.DataMinerWPF.Models.AuctionHouseSearchFilters" 
            xmlns:Models="clr-namespace:Codefarts.WowTracks.DataMinerAppCore.Models;assembly=Codefarts.WowTracks.DataMinerAppCore"
            xmlns:DataMinerAppCore="clr-namespace:Codefarts.WowTracks.DataMinerAppCore;assembly=Codefarts.WowTracks.DataMinerAppCore"
            xmlns:dataMinerWpf="clr-namespace:Codefarts.WowTracks.DataMinerWPF"
            x:Name="userControl"
            x:Class="Codefarts.WowTracks.DataMinerWPF.Controls.AuctionHouseSearchFilters.AuctionHouseItemNameControl" 
             mc:Ignorable="d" 
             d:DesignHeight="51" d:DesignWidth="283">
    <UserControl.Resources>
        <dataMinerWpf:UriToBitmapImageConverter x:Key="UriToImageConverter" />
        <BitmapImage x:Key='defaultImage' UriSource='/Resources\118.png' />
        <DataTemplate x:Key="ItemTemplate" DataType="Models:ItemDisplayModel" >
            <StackPanel Orientation="Horizontal" Margin="0 5 0 5">
                <Image Width="50" Height="50" Stretch="Fill" Source="{Binding IconUrl, Converter={StaticResource UriToImageConverter}, TargetNullValue={StaticResource defaultImage}}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                <Label Content="{Binding Name}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </StackPanel>
        </DataTemplate>

    </UserControl.Resources>
    <UserControl.DataContext>
        <AuctionHouseSearchFilters:AuctionHouseFilterItemNameModel/>
    </UserControl.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>
        <ComboBox x:Name="ItemList" MaxDropDownHeight="592" Grid.Row="0" ItemsSource="{Binding ItemDisplayModels}"   ItemTemplate="{StaticResource ItemTemplate}" IsEditable="True" IsTextSearchEnabled="True" IsTextSearchCaseSensitive="False" Text="{Binding Value}"    >

        </ComboBox>
    </Grid>
</UserControl>

这是我背后的代码

  public partial class AuctionHouseItemNameControl : UserControl, IAuctionHouseFilterControl
    {
        private Application app;

        public AuctionHouseItemNameControl()
        {
            InitializeComponent();
        }

        public void SetModel(IAuctionHouseSearchFilter model)
        {
            this.DataContext = model;
        }

        public void SetApplication(Application app)
        {
            this.app = app;
        }  

 private void ItemList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

            //if (model.Handled)
            //{
            //    return;   
            //}

            // model.Handled = true;
            if (e.AddedItems != null && e.AddedItems.Count > 0)
            {
                var model = this.DataContext as Models.AuctionHouseSearchFilters.AuctionHouseFilterItemNameModel;

                var item = e.AddedItems[0] as ItemDisplayModel;
                // this.ItemList.SelectedValue = item.Name;
                model.Value = item.Name;

                // this.ItemList.SelectedItem = item.Name;
            }

            //   model.Handled = false;
        }
    }

这是我的数据模型

 [Export(typeof(IAuctionHouseSearchFilter))]
    public class AuctionHouseFilterItemNameModel : IAuctionHouseSearchFilter, INotifyPropertyChanged
    {
        private string value;

        private bool connected;

        private Application app;

        private ItemDisplayModel[] displayItems;
        private CancellationTokenSource backgroundCancel;

        private bool buildingDisplayItems;

        private readonly object lockObject = new object();

        private ItemDisplayModel displayValue;

        //  private bool Handled { get; set; }
        public ItemDisplayModel DisplayValue
        {
            get
            {
                return this.displayValue;
            }
            set
            {
                if (value == null)
                {
                    return;
                }
                this.Value = value.Name;
                this.displayValue = value;
                this.OnPropertyChanged();
            }
        }

        public string Value
        {
            get
            {
                return this.value;
            }

            set
            {
                //if (this.Handled)
                //{
                //    return;
                //}

                if (value == this.value)
                {
                    return;
                }

                this.value = value;
              //  this.Handled = true;
                this.OnPropertyChanged();
                var cancellationTokenSource = this.backgroundCancel;
                if (cancellationTokenSource != null)
                {
                    cancellationTokenSource.Cancel();
                }

                this.BuildDisplayItems();
             //   this.Handled = false;
            }
        }

        public IEnumerable<AuctionDataModel> Filter(MainFilterModel model, IEnumerable<AuctionDataModel> items)
        {
            if (!this.connected)
            {
                return items;
            }

            // get item id from it's name
            var list = this.app.ItemNames[model.SelectedRegion];
            var id = list.FirstOrDefault(x => x.Name.ToLowerInvariant().Contains(this.value.Trim().ToLowerInvariant()));

            return items.Where(x => id != null && x.ItemId == id.Id);
        }

        public IEnumerable<ItemDisplayModel> ItemDisplayModels
        {
            get
            {
                return this.displayItems;
            }
        }

        public async void BuildDisplayItems()
        {
            if (this.buildingDisplayItems)
            {
                return;
            }

            if (!this.connected)
            {
                this.displayItems = null;
            }

            //  return this.GetDisplayItems();     
            this.buildingDisplayItems = true;
            this.backgroundCancel = new CancellationTokenSource();
            this.OnPropertyChanged("ItemDisplayModels");
            await Task.Factory.StartNew(
                    () =>
                    {
                        var originalItems = this.displayItems;
                        this.displayItems = new[] { new ItemDisplayModel() { Name = "Rebuilding list..." } };
                        var correctedSearchValue = this.value.Trim().ToLowerInvariant();
                        //lock (this.lockObject)
                        //{
                        this.displayItems = (string.IsNullOrWhiteSpace(this.value) ?
                                            this.app.DisplayItemModels :
                                            this.app.DisplayItemModels.Where(x => x.Name.ToLowerInvariant().Contains(correctedSearchValue))).Take(100).AsParallel().ToArray();

                        this.buildingDisplayItems = false;
                        this.OnPropertyChanged("ItemDisplayModels");
                    },
                    this.backgroundCancel.Token);
        }

        public string Name
        {
            get
            {
                return "Item Name";
            }
        }

        public Type Control
        {
            get
            {
                return typeof(AuctionHouseItemNameControl);
            }
        }

        public virtual IAuctionHouseSearchFilter Clone()
        {
            return new AuctionHouseFilterItemNameModel()
                       {
                           Value = this.Value
                       };
        }

        public void Connect(Application app)
        {
            if (this.connected)
            {
                return;
            }

            this.app = app;

            this.connected = true;
        }

        public void Disconnect()
        {
            if (!this.connected)
            {
                return;
            }

            this.app = null;
            this.connected = false;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

   public class ItemDisplayModel : INotifyPropertyChanged
    {
        private string iconUrl;

        private string region;

        private string name;

        private int itemId;

        public int ItemId
        {
            get
            {
                return this.itemId;
            }
            set
            {
                if (value == this.itemId)
                {
                    return;
                }
                this.itemId = value;
                this.OnPropertyChanged();
            }
        }

        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                if (value == this.name)
                {
                    return;
                }
                this.name = value;
                this.OnPropertyChanged();
            }
        }

        public string Region
        {
            get
            {
                return this.region;
            }
            set
            {
                if (value == this.region)
                {
                    return;
                }
                this.region = value;
                this.OnPropertyChanged();
            }
        }

        public string IconUrl
        {
            get
            {
                return this.iconUrl;
            }
            set
            {
                if (value == this.iconUrl)
                {
                    return;
                }
                this.iconUrl = value;
                this.OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

1 个答案:

答案 0 :(得分:1)

  

问题是当我点击一个项目时,我希望项目名称显示在组合框文本区域中。相反,我得到的是一个非常简短的ItemDisplayModel.ToString(),然后是一个空字符串。

要在Name使用TextSearch.TextPath的可编辑文本区域中显示ComboBox属性,以便ComboBox定义如下:

<ComboBox x:Name="ItemList"
          Grid.Row="0"
          IsEditable="True"
          IsTextSearchCaseSensitive="False"
          IsTextSearchEnabled="True"
          ItemTemplate="{StaticResource ItemTemplate}"
          ItemsSource="{Binding ItemDisplayModels}"
          MaxDropDownHeight="592"
          TextSearch.TextPath="Name" />

现在,当从下拉列表中选择某个项目而不是看到ItemDisplayModel.ToString()时,您会看到Name属性。