简体   繁体   English

WPF依赖的组合框不会显示.Net 4.5中的SelectedItem

[英]Wpf Depended combobox doesn't dispaly SelectedItem in .Net 4.5

I have main combobox (Categories) and depended combobox (Subcategories). 我有主组合框(类别)和从属组合框(子类别)。 I want it to display SelectedItems when window opens. 我希望它在窗口打开时显示SelectedItems。 All works fine in .Net 4.0, but it doesn't work in .Net 4.5. 在.Net 4.0中一切正常,但是在.Net 4.5中无效。 I have two computeres with these .Net versions. 我有两台具有这些.Net版本的计算机。

In .net 4.5. 在.net 4.5中。 only main combobox displays SelectedItem, depended doesn't. 仅主组合框显示SelectedItem,但不显示。 How can I fix it? 我该如何解决?

I made test project to all of you who're interested, just copy and paste. 我向所有感兴趣的人制作了测试项目,只需复制和粘贴即可。 I have no idea how I can make it smaller, sry. 我不知道如何缩小尺寸,对不起。 But it is simple, clear code example 100% generates the problem. 但是它很简单,清晰的代码示例100%会产生问题。

XAML: XAML:

<Window x:Class="GridTest.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Converter="clr-namespace:GridTest"
        Title="TestWindow" 
        Height="300" 
        Width="300">
    <Window.Resources>
        <Converter:CategoryConverter x:Key="CategoryConverter"/>
    </Window.Resources>
        <Grid>
        <DataGrid Name="_dataGrid" 
                  CanUserAddRows="False" 
                  AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTemplateColumn Width="*">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>
                                    <ColumnDefinition/>
                                </Grid.ColumnDefinitions>
                                <ComboBox Grid.Column="0" 
                                          Name="_categories" 
                                          ItemsSource="{Binding Categories}" 
                                          DisplayMemberPath="Name" 
                                          SelectedItem="{Binding SelectedCategory, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
                                </ComboBox>
                                <ComboBox Grid.Column="1" 
                                          SelectedItem="{Binding SelectedSubcategory, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                          DisplayMemberPath="Name">
                                    <ComboBox.ItemsSource>
                                        <MultiBinding Converter="{StaticResource CategoryConverter}">
                                            <Binding Path="Subcategories"/>
                                            <Binding Path="SelectedItem" 
                                                     ElementName="_categories"/>
                                        </MultiBinding>
                                    </ComboBox.ItemsSource>
                                </ComboBox>
                            </Grid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Code: 码:

public class CategoryConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values[0] == null) return null;

            var subcategories = values[0] as List<Subcategory>;
            if (subcategories == null) return null;

            var category = values[1] as Category;
            if (category == null) return subcategories;

            return subcategories.Where(g => g.CategoryId == category.Id);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }


    public enum CategoryKinds
    {
        Car = 0,
        Fruit = 1,
    }

    public class Category
    {
        public Int32 Id { get; set; }
        public String Name { get; set; }

        public override Boolean Equals(object obj)
        {
            var c = obj as Category;
            if (c == null) return false;

            return Id == c.Id;
        }
    }

    public class Subcategory
    {
        public Int32 Id { get; set; }
        public String Name { get; set; }
        public Int32 CategoryId { get; set; }


        public override Boolean Equals(object obj)
        {
            var sc = obj as Subcategory;
            if (sc == null) return false;

            return Id == sc.Id;
        }
    }

    public class DataGridItem 
    {
        public List<Category> Categories { get; set; }
        public Category SelectedCategory { get; set; }

        public List<Subcategory> Subcategories { get; set; }
        public Subcategory SelectedSubcategory { get; set; }

        public DataGridItem()
        {
            Categories = new List<Category>
            {
                new Category
                {
                    Id = (Int32)CategoryKinds.Car, Name = "Car"
                },
                new Category
                {
                    Id = (Int32)CategoryKinds.Fruit, Name = "Fruit"
                }
            };

            Subcategories = new List<Subcategory>
            {
                new Subcategory
                {
                    Id = 1,
                    Name = "Volvo",
                    CategoryId = (Int32) CategoryKinds.Car
                },
                new Subcategory
                {
                    Id = 2,
                    Name = "Nissan",
                    CategoryId = (Int32) CategoryKinds.Car
                },
                new Subcategory
                {
                    Id = 3,
                    Name = "Banana",
                    CategoryId = (Int32)CategoryKinds.Fruit
                },
                new Subcategory
                {
                    Id = 4,
                    Name = "Lemon",
                    CategoryId = (Int32)CategoryKinds.Fruit
                },
            };
        }
    }

    /// <summary>
    /// Interaction logic for TestWindow.xaml
    /// </summary>
    public partial class TestWindow : Window
    {
        public List<DataGridItem> GridItems { get; set; }

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

            GridItems = new List<DataGridItem>
            {
                new DataGridItem
                {
                    SelectedCategory = new Category
                    {
                        Id = (Int32)CategoryKinds.Car, Name = "Car"
                    },
                    SelectedSubcategory = new Subcategory
                    {
                        Id = 2,
                        Name = "Nissan",
                        CategoryId = (Int32) CategoryKinds.Car
                    }
                },
                new DataGridItem
                {
                    SelectedCategory = new Category
                    {
                        Id = (Int32)CategoryKinds.Fruit, Name = "Fruit"
                    },
                    SelectedSubcategory = new Subcategory
                    {
                        Id = 4,
                        Name = "Lemon",
                        CategoryId = (Int32) CategoryKinds.Car
                    }
                }
            };

            _dataGrid.ItemsSource = GridItems;
        }
    }

UPDATE 更新

With approach suggested by Ilan and charly_b code will work fine. 使用Ilan和charly_b建议的方法,代码可以正常工作。

GridItems = new List<DataGridItem>
            {
                new DataGridItem(),
                new DataGridItem()
            };

            GridItems[1].SelectedCategory = GridItems[1].Categories[0];
            GridItems[1].SelectedSubcategory = GridItems[1].Subcategories[1];

            GridItems[0].SelectedCategory = GridItems[0].Categories[1];
            GridItems[0].SelectedSubcategory = GridItems[0].Subcategories[3];

This code will result to: 该代码将导致:

  1. Fruit - Lemon 水果-柠檬
  2. Car - Nissan 汽车-日产

But I have solution that will work even if you set SelectedItem that don't belong to ItemsSource of Combobox. 但是,即使您设置了不属于Combobox的ItemsSource的SelectedItem,我也有解决方案。 You can override GetHashCode method like this: 您可以像这样重写GetHashCode方法:

public override int GetHashCode()
        {
            return Name.GetHashCode();
        }

Obviously, in .Net 4.5 some of WPF methods operating with searching SelectedItem in Combobox's ItemsSource have different implementation from .Net 4.0 and now they use GetHashCode method :) 显然,在.Net 4.5中,一些在Combobox的ItemsSource中搜索SelectedItem的WPF方法与.Net 4.0具有不同的实现,现在它们使用GetHashCode方法:)

The Combobox SelectedItem object must be contained inside the Combobox's ItemsSource List. Combobox SelectedItem对象必须包含在Combobox的ItemsSource列表中。

In order to make your Programm work you can replace the SelectedSubCategory Property with the following code: (I would not use it like this in the production code, but it demonstrates how it works) 为了使您的Programm正常工作,您可以使用以下代码替换SelectedSubCategory属性:(我不会在生产代码中使用它,但是它演示了它的工作原理)

    private Subcategory SelectedSubcategoryM;

    public Subcategory SelectedSubcategory
    {
        get
        {
            return this.SelectedSubcategoryM;
        }
        set
        {
            this.SelectedSubcategoryM = (from aTest in this.Subcategories
                                        where aTest.Id == value.Id
                                        select aTest).Single();
        }
    }

Try the next changes, the best practice is to use the source collection items in order to define the selected item. 尝试下一个更改,最佳实践是使用源集合项以定义选定的项。 Firstly it is an architectural error to use a new item to define the selection (in both 4.5 and 4 dot.net versions). 首先,使用新项目定义选择(在4.5和4 dot.net版本中)都是体系结构错误。 And second I advice you to use the mvvm approach (including INotifyPropertyChange implementation) to develop wpf related applications, and then all selection logic have to be moved to ViewModel and separated from the code behind (xaml.cs files). 其次,我建议您使用mvvm方法(包括INotifyPropertyChange实现)来开发与wpf相关的应用程序,然后所有选择逻辑都必须移至ViewModel并与后面的代码(xaml.cs文件)分开。

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

        var f = new DataGridItem();
        var firstselectedCategory = f.Categories.FirstOrDefault();
        if (firstselectedCategory != null)
        {
            f.SelectedCategory = firstselectedCategory;
            f.SelectedSubcategory =
                f.Subcategories.FirstOrDefault(subcategory => subcategory.CategoryId == firstselectedCategory.Id);
        }
        else
        {

            f.SelectedCategory = null;
            f.SelectedSubcategory = null;
        }
        var s = new DataGridItem();
        var secondSelectedCategory = s.Categories.FirstOrDefault(category => !Equals(category, f.SelectedCategory));

        if (secondSelectedCategory != null)
        {
            s.SelectedCategory = secondSelectedCategory;
            s.SelectedSubcategory =
                s.Subcategories.FirstOrDefault(subcategory => subcategory.CategoryId == secondSelectedCategory.Id);
        }
        else
        {
            s.SelectedCategory = null;
            s.SelectedSubcategory = null;
        }

        GridItems = new List<DataGridItem>
        {
            f,s,
        };

    #region

        //GridItems = new List<DataGridItem>
        //{
        //    new DataGridItem
        //    {
        //        SelectedCategory = new Category
        //        {
        //            Id = (Int32) CategoryKinds.Car,
        //            Name = "Car"
        //        },
        //        SelectedSubcategory = new Subcategory
        //        {
        //            Id = 2,
        //            Name = "Nissan",
        //            CategoryId = (Int32) CategoryKinds.Car
        //        }
        //    },
        //    new DataGridItem
        //    {
        //        SelectedCategory = new Category
        //        {
        //            Id = (Int32) CategoryKinds.Fruit,
        //            Name = "Fruit"
        //        },
        //        SelectedSubcategory = new Subcategory
        //        {
        //            Id = 4,
        //            Name = "Lemon",
        //            CategoryId = (Int32) CategoryKinds.Fruit
        //        }
        //    }
        //};

        #endregion


        _dataGrid.ItemsSource = GridItems;
    }

The xaml code was not changed. xaml代码未更改。 How it looks like: 看起来如何: 这里 . I'll be glad to help if will have problems with the code. 如果代码有问题,我将很乐意提供帮助。 Regards. 问候。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM