2

간결하게 설명하겠습니다. ItemTemplate을 구현하는 ListBox가 있습니다. DataTemplate에는 확인란이 있습니다. 약 2000 항목을로드합니다. 처음 5 개 항목을 확인하고 하단으로 스크롤하여 마지막 5 개 항목을 선택합니다. 그런 다음 맨 위 항목으로 스크롤하고 처음 5 개의 체크 항목이 수정되었음을 확인했습니다.ItemsControl의 항목과 관련된 렌더링 문제

<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에서 발생합니다. VirtualizingStackPanel.IsVirtualizing이 false로 설정되면이 동작은 발생하지 않지만 실제 상황에서는 가상화를 사용하지 않고로드하는 것이 쉽지 않습니다.

몇 가지 통찰력이 좋을 것입니다. 사전에

감사합니다,

안드레스 올리바 레스

답변

2

그 안에 컨트롤을 재-사용하고 단순히 스크롤 컨트롤 뒤에 DataContext을 대체 가상화 된 패널. 이것은 스크롤 할 때 컨트롤의 상태 (예 : IsChecked)가 해당 상태가 DataContext의 무언가에 바인딩되어 있지 않으면 재설정된다는 것을 의미합니다.

예를 들어 한 번에 10 개의 항목 만 표시되는 경우 WPF는 약 14 개 (스크롤 버퍼의 추가 항목) 만 렌더링하고 스크롤하고 대치하면이 14 개의 항목을 다시 사용하기 만하면됩니다 컨트롤 뒤의 DataContext.

가상화를 사용하지 않도록 설정하면이 재활용 동작을 사용할 수 없게됩니다. 이것은 WPF가 14 개가 아닌 2000 개의 항목을 렌더링한다는 것을 의미합니다. 따라서 성능이 그렇게 나쁩니다. 또한 상태가 재설정되지 않기 때문에 CheckBoxes가 계속 확인됨을 의미합니다.

이 문제를 해결하려면 사용자 개체에 IsSelected 속성을 추가하고 CheckBox.IsChecked을 바인딩하는 것이 좋습니다.

+0

레이첼 감사합니다. 지금까지 제안한 바에 따르면 UI에서 동작을 설명하는 모델에 속성을 추가하는 것이 허용되는 패턴이라고 생각하지 않습니다. 나는이 주장이 매우 대중적이라고 생각하지만 이것이 합리적인 해결책이라고 생각하지 않는다. 제공된 설명에 따라 스크롤하는 동안 DataContext의 손실이 손실되거나 복원되지 않는 솔루션을 선호합니다. 나는이 딜레마에 대해 좀 더 설명해야하지만이 노력에 대해 더 많이 게시 할 예정이지만 관심을 가져 주셔서 대단히 감사드립니다. –

+0

@AndresOlivares'IsSelected'와'User' 객체에 대한 속성을 포함하는 클래스를 생성 한 다음 ViewModel에'List '을 사용하지 않고 객체 목록을 생성 할 수 있습니다. 필자가 과거에 사용한 또 다른 방법은'IsChecked'를'ListBoxItem.IsSelected' 속성에 바인딩하여 ListBox가 여러 항목을 선택하고 ListBox의 선택 기능을 숨길 수있게하는 것입니다. 이 기능은 선택 기능을 사용하지 않는 경우에만 작동합니다. – Rachel