Проблемы с отображением элементов в ItemsControl - PullRequest
2 голосов
/ 05 января 2012

Я буду кратким.У меня есть ListBox, который реализует ItemTemplate.DataTemplate содержит флажок.Я загружаю около 2000 штук.Я проверяю первые 5 пунктов, прокручиваю вниз и выбираю последние 5 элементов.Затем я прокручиваю вверх до верхнего элемента и заметил, что мои первые 5 элементов проверки были изменены.

    <Window 
        x:Class="CheckItems.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CheckItems"
        Title="Window1" Height="300" Width="300"
        >
        <DockPanel>
            <StackPanel DockPanel.Dock="Bottom" >
                <Button Content="Test" Click="Button_Click"/>
            </StackPanel>
            <ListBox DockPanel.Dock="Left"
                x:Name="users"
                ItemsSource="{Binding Path=Users}"
                >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <CheckBox>
                            <TextBlock Text="{Binding Path=Name}"/>
                        </CheckBox>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </DockPanel>
    </Window>



    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Windows;
    namespace CheckItems
    {
        public partial class Window1 : Window
        {
            ViewModel controller;

            public Window1()
            {
                DataContext = controller = new ViewModel();
                InitializeComponent();
                controller.Users = LoadData();
            }

            private List<User> LoadData()
            {
                var newList = new List<User>();
                for (var i = 0; i < 2000; ++i)
                    newList.Add(new User { Name = "Name" + i, Age = 100 + i });
                return newList;
            }

            private void Button_Click(object sender, RoutedEventArgs e)
            { }
        }

        public class User
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }


        public class ViewModel : INotifyPropertyChanged
        {
            private List<User> users;
            public event PropertyChangedEventHandler PropertyChanged;

            public List<User> Users
            {
                get { return users; }
                set { users = value; NotifyChange("Users"); }
            }

            protected void NotifyChange(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

Надеюсь, есть хорошее объяснение этому, кроме того - это ошибка MS.Это происходит в .NET 3.5 и 4.0.Когда VirtualingStackPanel.IsVirtualizing имеет значение false, такое поведение не происходит, но в реальном мире загрузка без виртуализации является болезненной.

Некоторое понимание было бы неплохо.

Заранее спасибо,

Андрес Оливарес

1 Ответ

2 голосов
/ 05 января 2012

Виртуализирующая панель повторно использует элементы управления в ней и просто заменяет DataContext за элементами управления при прокрутке.Это означает, что при прокрутке состояние элемента управления (например, IsChecked) сбрасывается, если только это состояние не связано с чем-либо в DataContext.

Например, если видны только 10 элементов вашего 2000за один раз WPF будет отображать только около 14 из них (дополнительные элементы для буфера прокрутки) и просто повторно использовать эти 14 элементов при прокрутке и замене DataContext за элементами управления.

Если вы отключите виртуализацию, вы отключите эту процедуру утилизации.Это означает, что WPF будет отображать 2000 элементов вместо 14, поэтому производительность настолько низкая.Это также означает, что флажки останутся проверенными, поскольку их состояние не сбрасывается.

Чтобы исправить эту проблему, я бы рекомендовал добавить свойство IsSelected к вашему объекту пользователя и привязать к нему CheckBox.IsChecked.

...