Что заставляет мои элементы со списком WPF так долго обновляться при изменении источника элементов?

У меня есть сетка данных (назовем ее dat1), в которой источник элементов привязан к наблюдаемой коллекции пользовательского типа, назовем ее TypeA. Одно из свойств TypeA — это наблюдаемая коллекция другого пользовательского типа, назовем его TypeB. Затем у меня есть поле со списком с источником элементов, привязанным к SelectedItem.TypeB dat1.

Поэтому, когда пользователь выбирает TypeA в dat1, в поле со списком отображаются элементы наблюдаемой коллекции TypeB из выбранного TypeA. Есть смысл?

Привязка ДЕЙСТВИТЕЛЬНО работает и ДЕЙСТВИТЕЛЬНО обновляется. Проблема заключается в том, что когда презентатор элементов в поле со списком уже отображал элементы, а пользователь выбирает другой тип A в dat1 и пытается просмотреть новые элементы в поле со списком, возникает длительная пауза, в то время как презентатор элементов создает новые элементы.

Чтобы проверить проблему, я могу упростить сценарий.

Действия по воспроизведению:

  1. Создайте новый проект WPF с помощью .NET 4.0.

  2. Вырежьте и вставьте код ниже.

  3. Чтобы получить поведение замораживания, вы должны перетащить поле со списком, чтобы увидеть элементы, затем нажать кнопку, чтобы изменить источник элементов, а затем снова удалить поле со списком. Поле со списком падает через несколько секунд, но почему так медленно?

XAML

<Window x:Class="ComboBoxTest.MainWindow"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <ComboBox x:Name="cbo" DisplayMemberPath="Junk1"></ComboBox>
            <Button Content="Click Me!" Click="btn_Click"></Button>
        </StackPanel>
    </Grid>
</Window>

Код

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.cbo.ItemsSource = junk1;
    }

    ObservableCollection<Junk> junk1 = new ObservableCollection<Junk>() {
        new Junk() { Junk1 = "junk1 - 1" },
        new Junk() { Junk1 = "junk1 - 2" } };

    ObservableCollection<Junk> junk2 = new ObservableCollection<Junk>() {
        new Junk() { Junk1 = "junk2 - 1" },
        new Junk() { Junk1 = "junk2 - 2" },
        new Junk() { Junk1 = "junk2 - 3" },
        new Junk() { Junk1 = "junk2 - 4" } };

    private void btn_Click(object sender, RoutedEventArgs e)
    {
        if (this.cbo.ItemsSource == junk1)
            this.cbo.ItemsSource = junk2;
        else
            this.cbo.ItemsSource = junk1;
    }
}

public class Junk
{
    public string Junk1 { get; set; }
}

ПРИМЕЧАНИЕ. Это проблема WPF. Я слышал, что в Silverlight такой проблемы нет. Мне не нужно знать, работает ли Silverlight. Мне нужен ответ WPF.

PS. Задержка больше, когда источник элементов изменяется на мусор2, предположительно, потому, что он больше.

Это настолько задерживает, что я думаю, что это может быть вызвано привязкой исключений, поскольку исключения требуют времени. Есть ли способ узнать, возникают ли исключения привязки?


person John    schedule 10.12.2010    source источник
comment
Вы должны видеть исключения привязки в окне вывода в VS IDE во время отладки.   -  person VoodooChild    schedule 10.12.2010
comment
Я не вижу долгой паузы с кодом, который вы разместили.   -  person lesscode    schedule 10.12.2010
comment
Так же и здесь, похоже, нет никаких колебаний.   -  person Mark Hall    schedule 10.12.2010


Ответы (1)


Я тоже наблюдаю это явление. Я использую Visual Studio 2010 (с ReSharper 6.0) в Windows 7 x64.

Это не заметно только с четырьмя элементами, как в приведенном выше примере, но если я сделаю это, например. 50 и более предметов зависание становится очень заметным. После повторной привязки он зависнет примерно на 15 секунд, прежде чем мне снова разрешат взаимодействовать с ним.

Еще интересно, что это происходит только при отладке в VS. Если я запускаю автономный exe, он действительно быстрый и быстрый.

Вот код из моего простого проекта:

XAML

<Window x:Class="ComboBoxFreeze.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
  <StackPanel>
    <ComboBox x:Name="cbo" DisplayMemberPath="Junk1"></ComboBox>
    <Button Content="Click Me!" Click="btn_Click"></Button>
  </StackPanel>
</Window>

Код

using System.Collections.ObjectModel;
using System.Windows;

namespace ComboBoxFreeze
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;

            _junk1 = new ObservableCollection<Junk>();
            for (int i = 0; i < 50; i++)
            {
                _junk1.Add(new Junk { Junk1 = "Prop1a-" + i, Junk2 = "Prop1b-" + i });
            }


            _junk2 = new ObservableCollection<Junk>();
            for (int i = 0; i < 50; i++)
            {
                _junk2.Add(new Junk { Junk1 = "Prop2a-" + i, Junk2 = "Prop2b-" + i });
            }
        }

        private readonly ObservableCollection<Junk> _junk1;

        private readonly ObservableCollection<Junk> _junk2;

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            cbo.ItemsSource = _junk1;
        }

        private void btn_Click(object sender, RoutedEventArgs e)
        {
            if (cbo.ItemsSource == _junk1)
            {
                cbo.ItemsSource = _junk2;
            }
            else
            {
                cbo.ItemsSource = _junk1;
            }
        }
    }

    public class Junk
    {
        public string Junk1 { get; set; }
        public string Junk2 { get; set; }
    }
}

Я опубликую здесь снова, если найду решение или обходной путь.

person SteffenSH    schedule 22.09.2011
comment
Работая на моем ноутбуке в VS2008, Win7 x64, Resharper 5.1, этот код работает очень быстро. Здесь нет проблем с колебаниями. Интересно, стоит ли публиковать полный вывод отладки при запуске этого на вашем компьютере. Возможно, изучение загружаемых версий сборки может дать некоторое представление. - person RMart; 22.09.2011