2010-12-30 4 views
1

문제는 내 listcollectionview가 업데이트하는 데 3-4 초가 걸리는 것입니다. 가상화가 제대로 구성되어 있다고 생각합니다. 그러나 그것이 틀렸다는 것을 지적하십시오. 내 itemssource는 ICollectionView에 바인딩되어 있습니다.느린 wpf ItemsControl ListCollectionView에서 새로 고침

BindingViewModel에서 루프를 3000+ 이상으로 설정하면 UI가 ViewModels를 작성하는 데 1 초도 걸리지 않지만 시작하는 데 오랜 시간이 걸립니다.

BigList.Xaml : `

<Style x:Key="textBlockBaseStyle" TargetType="TextBlock"> 
     <Setter Property="Foreground" Value="Blue"/> 
    </Style> 

    <Style x:Key="headerButtonStyle" TargetType="Button"> 
     <Setter Property="FontWeight" Value="Bold"/> 
     <Setter Property="Foreground" Value="Blue"/> 
     <Setter Property="Background" Value="Transparent" /> 
     <Setter Property="HorizontalContentAlignment" Value="Stretch"/> 
     <Setter Property="BorderBrush" Value="Transparent"/> 
     <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="True"> 
       <Setter Property="Background" Value="DarkBlue"/> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 

    <Style x:Key="borderBaseStyle" TargetType="Border"> 
     <Setter Property="BorderBrush" Value="Blue"/> 
    </Style> 

    <!--these two styles let us cascadingly style on the page without having to specify styles 
     apparently styles don't cascade into itemscontrols... in the items control we must reference via key --> 

    <Style TargetType="TextBlock" BasedOn="{StaticResource textBlockBaseStyle}"/> 
    <Style TargetType="Border" BasedOn="{StaticResource borderBaseStyle}"/> 

    <!-- hover styles --> 
    <Style x:Key="onmouseover" TargetType="{x:Type Border}" BasedOn="{StaticResource borderBaseStyle}"> 
     <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="True"> 
       <Setter Property="Background" Value="DarkBlue"/> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 

</UserControl.Resources> 
<Grid> 
    <StackPanel Width="390"> 
    <!-- Header--> 
    <Border BorderThickness="1,1,1,1"> 
     <Grid> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="55"/> 
       <ColumnDefinition Width="70"/> 
       <ColumnDefinition Width="70"/> 
       <ColumnDefinition Width="70"/> 
       <ColumnDefinition Width="70"/> 
      </Grid.ColumnDefinitions> 

      <Button Command="{Binding SortFirstNameCommand}" Style="{StaticResource headerButtonStyle}" Grid.Column="1" > 
       <TextBlock TextAlignment="Left" Text="First"/> 
      </Button> 
      <Button Style="{StaticResource headerButtonStyle}" Grid.Column="2" > 
       <TextBlock TextAlignment="Left" Text="Last"/> 
      </Button> 
      <Button Style="{StaticResource headerButtonStyle}" Grid.Column="3" > 
       <TextBlock TextAlignment="Left" Text="Activity"/> 
      </Button> 
      <Button Style="{StaticResource headerButtonStyle}" Grid.Column="4"> 
       <TextBlock TextAlignment="Left" Text="Last Activity"/> 
      </Button> 
     </Grid> 
    </Border> 
    <Border BorderThickness="1,0,1,1"> 
     <ItemsControl VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" ItemsSource="{Binding UsersAvailForEmail}" MaxHeight="400"> 
      <ItemsControl.Template> 
       <ControlTemplate> 
        <ScrollViewer x:Name="ScrollViewer" HorizontalScrollBarVisibility="Disabled" 
                  VerticalScrollBarVisibility="Auto" IsDeferredScrollingEnabled="True" Padding="{TemplateBinding Padding}"> 
         <ItemsPresenter/> 
        </ScrollViewer> 
       </ControlTemplate> 
      </ItemsControl.Template> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <Border Style="{StaticResource onmouseover}" BorderThickness="0,0,1,1"> 
         <CheckBox Margin="20,5" IsChecked="{Binding IsSelected}"> 
          <CheckBox.Content> 
           <StackPanel Orientation="Horizontal"> 
            <TextBlock Width="20"/> 
            <TextBlock Width="70" Style="{StaticResource textBlockBaseStyle}" Grid.Column="1" Text="{Binding FirstName}"/> 
            <TextBlock Width="70" Style="{StaticResource textBlockBaseStyle}" Grid.Column="2" Text="{Binding LastName}"/> 
            <TextBlock Width="70" Style="{StaticResource textBlockBaseStyle}" Grid.Column="3" Text="{Binding Action}"/> 
            <TextBlock Width="60" Style="{StaticResource textBlockBaseStyle}" Grid.Column="4" Text="{Binding ActionId}"/> 
           </StackPanel> 
          </CheckBox.Content> 
         </CheckBox> 
        </Border> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 

    </Border> 
</StackPanel> 


</Grid> 

`

나는이 문제를 재현하는 모든 샘플 코드를 게시합니다 있도록 파일을 첨부하는 방법을 모른다

BindingViewModel.cs :

using System.Linq; 
using System.Text; 
using System.ComponentModel; 
using System.Collections.ObjectModel; 
using System.Windows.Data; 

namespace LargeItemsCollection 
{ 
    public class BindingViewModel : INotifyPropertyChanged 
    { 
     ObservableCollection<EmailPersonViewModel> _usersAvail = new ObservableCollection<EmailPersonViewModel>(); 
     ListCollectionView _lvc = null; 

     public BindingViewModel() 
     { 

      for (int i = 0; i < 4000; i++) 
      { 
       _usersAvail.Add(new EmailPersonViewModel { FirstName = "f" +i.ToString() , LastName= "l" + i.ToString(), Action= "a" + i.ToString(), ActionId="ai" + i.ToString(), IsSelected=true }); 
      } 

      _lvc = new ListCollectionView(_usersAvail); 

     } 

     public ICollectionView UsersAvailForEmail 
     { 
      get { return _lvc; } 
     } 


     /// <summary> 
     /// Raised when a property on this object has a new value. 
     /// </summary> 
     public event PropertyChangedEventHandler PropertyChanged; 

     /// <summary> 
     /// Raises this object's PropertyChanged event. 
     /// </summary> 
     /// <param name="propertyName">The property that has a new value.</param> 
     public virtual void OnPropertyChanged(string propertyName) 
     { 
      PropertyChangedEventHandler handler = this.PropertyChanged; 
      if (handler != null) 
      { 
       var e = new PropertyChangedEventArgs(propertyName); 
       handler(this, e); 
      } 
     } 
    } 

EmailPersonViewModel.cs :

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace LargeItemsCollection 
{ 
    public class EmailPersonViewModel 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public string Action { get; set; } 
     public string ActionId { get; set; } 

     public bool IsSelected { get; set; } 

     public EmailPersonViewModel() 
     { 

     } 

    } 
} 

MainWindow.xaml :

<Window x:Class="LargeItemsCollection.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:LargeItemsCollection" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <local:BigList/> 
    </Grid> 
</Window> 

MainWindow.cs :

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace LargeItemsCollection 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      DataContext = new BindingViewModel(); 
     } 
    } 
} 

답변

1

모든 우완 투수가 :

Virtualizing a WPF ItemsControl

나는 Scrollviewer.CanScroll =이 없었다 '진정한'WPF의 virtualizationstackpanel에 그것없이 작동하지 않습니다.

나를 도울 수있는 해결책을 게시 한 모든 분들께 감사드립니다. 너희들은 그 해결책을 찾지 못했고 나는 그것을 올바르게 표시하지 않았다. 그러나 나는 너희들 둘 다 길을 따라 도왔 기 때문에 너희들에게 상향 줄을 주었다. 다음은 최종 XAML이므로 itemscontrol이 어떤 모습인지 확인할 수 있습니다.

<ItemsControl ScrollViewer.CanContentScroll="True" VirtualizingStackPanel.VirtualizationMode="Recycling" ItemsSource="{Binding UsersAvailForEmail}" MaxHeight="400"> 
        <ItemsControl.ItemsPanel> 
         <ItemsPanelTemplate> 
          <VirtualizingStackPanel /> 
         </ItemsPanelTemplate> 
        </ItemsControl.ItemsPanel> 
          <ItemsControl.Template> 
        <ControlTemplate> 
         <ScrollViewer x:Name="ScrollViewer" HorizontalScrollBarVisibility="Disabled" 
                   VerticalScrollBarVisibility="Auto" IsDeferredScrollingEnabled="True" Padding="{TemplateBinding Padding}"> 
          <ItemsPresenter/> 
         </ScrollViewer> 
        </ControlTemplate> 
       </ItemsControl.Template> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 

         <Border Style="{StaticResource onmouseover}" BorderThickness="0,0,1,1"> 
          <CheckBox Margin="20,5" IsChecked="{Binding IsSelected}"> 
           <CheckBox.Content> 
            <StackPanel Orientation="Horizontal"> 
             <TextBlock Width="20"/> 
             <TextBlock Width="70" Style="{StaticResource textBlockBaseStyle}" Grid.Column="1" Text="{Binding FirstName}"/> 
             <TextBlock Width="70" Style="{StaticResource textBlockBaseStyle}" Grid.Column="2" Text="{Binding LastName}"/> 
             <TextBlock Width="70" Style="{StaticResource textBlockBaseStyle}" Grid.Column="3" Text="{Binding Action}"/> 
             <TextBlock Width="60" Style="{StaticResource textBlockBaseStyle}" Grid.Column="4" Text="{Binding ActionId}"/> 
            </StackPanel> 
           </CheckBox.Content> 
          </CheckBox> 
         </Border> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 
1

나는 당신이 찍은 정렬 방식에 의한 같아요. 후드 아래에서 반사를 사용하고 이것은 병목 현상입니다. ListCollectionView 클래스의 CustomSort 속성을 사용하는 것이 좋습니다. 이 answer의 링크를 클릭하십시오.

희망이 도움이됩니다.

+0

CustomSort에 추가하고 정렬 시간을 줄였습니다. 위에서 설명한 그리드는 여전히 5 초가 걸립니다. 데이터 구조에서 객체 구성이나 그리드 사용과 관련이 있다고 생각합니다. 호출 스택의 지연 중에 Ctrl + Alt + Break를 누르면 [외부 코드]가 표시됩니다. –

2

가상화 스택 패널은 ItemsSource에있는 객체가 아니라 시각적 트리에서 객체 생성을 가상화합니다. 컨트롤이 바인딩 된 뷰 모델 개체 컬렉션을 만드는 데 4 초가 걸리면 가상화를 사용하는지 여부에 관계없이 컨트롤을 표시하는 데 4 초가 걸립니다.

컬렉션을 정렬하기 때문에 컬렉션에있는 모든 항목을 인스턴스화해야 컨트롤에서 그 중 하나를 표시 할 수 있습니다. 그러나 4,000 개의 모든 객체를 구성하는 데 오랜 시간이 걸리는 것은 고정 된 비용입니다.

쉽게 테스트 할 수있는 방법은 개체 컬렉션을 만드는 명령과 컬렉션에 바인딩 된 항목 컨트롤을 표시하는 두 번째 명령을 만드는 것입니다. 그런 다음 UI를보고 각 항목을 개별적으로 수행하는 데 걸리는 시간을 확인할 수 있습니다.

실제로 문제가되는 경우 개체 생성 속도를 높이는 데 집중할 수 있습니다 (예 : 액세스에 시간이 많이 걸리는 속성에 대한 지연 평가를 사용하여 정렬에 사용되지 않는다고 가정) 백그라운드에서 컬렉션입니다. 이 게시물 당

+0

답장을 보내 주셔서 감사합니다. 내 Object 생성에 타이머를 두었습니다.이 타이머는 초 미만이었습니다 (dbPreview는 EmailPersonViewModel을 통과하지 못했습니다). 샘플 프로젝트에서 문제를 재현하여 위에 게시했습니다. UI 가상화 설정을 조정하고 어떤 일이 일어나는지 살펴볼 것입니다. –

관련 문제