Wpf Depended combobox не отображает выбранный элемент в.Net 4.5

У меня есть основной комбинированный список (Категории) и зависимый комбинированный список (Подкатегории). Я хочу, чтобы он отображал SelectedItems при открытии окна. Все отлично работает в.Net 4.0, но не работает в.Net 4.5. У меня есть два компьютера с этими версиями.Net.

В.net 4.5. SelectedItem отображает только основной выпадающий список, но не зависит. Как я могу это исправить?

Я сделал тестовый проект для всех вас, кто заинтересован, просто скопируйте и вставьте. Я понятия не имею, как я могу сделать это меньше, сри. Но это простой, понятный пример кода 100% порождает проблему.

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>

Код:

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

ОБНОВИТЬ

С подходом, предложенным Иланом, код 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];

Этот код приведет к:

  1. Фрукты - лимон
  2. Автомобиль - Nissan

Но у меня есть решение, которое будет работать, даже если вы установите SelectedItem, который не принадлежит ItemsSource в Combobox. Вы можете переопределить GetHashCode метод как это:

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

Очевидно, что в.Net 4.5 некоторые методы WPF, работающие с поиском SelectedItem в ItemsSource Combobox, имеют реализацию, отличную от.Net 4.0, и теперь они используют метод GetHashCode:)

2 ответа

Решение

Попробуйте следующие изменения, лучше всего использовать исходные элементы коллекции для определения выбранного элемента. Во-первых, это архитектурная ошибка - использовать новый элемент для определения выбора (как в 4.5, так и в 4 версиях dot.net). И во-вторых, я советую вам использовать подход 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;
    }

Код xaml не был изменен. Как это выглядит: Вот, Я буду рад помочь, если возникнут проблемы с кодом. С уважением.

Объект Combobox SelectedItem должен содержаться внутри списка ItemsSource Combobox.

Чтобы заставить вашу Программу работать, вы можете заменить Свойство 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();
        }
    }
Другие вопросы по тегам