2012-12-14 1 views
5

표시 할 데이터와 같은 거대한 테이블이있는 응용 프로그램에서 뷰가 있습니다. 데이터는 두 개의 중첩 된 UniformGrid에 표시됩니다. UniformGrid는 ItemsControls의 ItemPanels이며 일부 ViewModel에 바인딩됩니다. 다음 이미지와 몇 가지 예를 들어 XAML 코드를 참조하십시오거대한 UniformGrid에서 성능을 처리하는 방법은 무엇입니까?

view and viewmodel http://img593.imageshack.us/img593/8825/stackoverflowuniformgri.png

<!-- The green boxes --> 
<ItemsControl ItemsSource="{Binding BigCells}"> 

    <ItemsControl.ItemPanel> 
    <PanelTemplate> 
     <UniformGrid /> 
    </PanelTemplate> 
    </ItemsControl.ItemPanel> 

    <ItemsControl.ItemTemplate> 
    <DataTemplate> 

     <!-- The blue boxes --> 
     <ItemsControl ItemsSource="{Binding SmallCells}"> 
     <ItemsControl.ItemPanel> 
      <PanelTemplate> 
      <UniformGrid /> 
      </PanelTemplate> 
     </ItemsControl.ItemPanel> 
     </ItemsControl> 

    </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

지금, 내보기 크기 조정되고 싶어하지만,이 모든 단일 작은 상자의 레이아웃이 계산되는 모든 이후에 잘 수행하지 않습니다.
적어도 모든 상자에 대해 동일하므로 상자 크기는 한 번만 수행 할 수 있습니다.

WPF에서 막대한 양의 컨트롤을 표시하는 것이 가장 좋습니다./어디에서 최적화를 시작할 수 있습니까? 키워드를 사용하면 WPF의 UniformGrid에 대한 성능 최적화를 계속해서 발견 할 수 있습니다.

답변

8

WPF DataGrid을 많이 사용하면 비슷한 문제가 발생합니다. 당신은 기본 WPF가주의하지 않고 기능을 사용하는 경우 그 주요 병목이 될 수

리소스 사전을

  • 리소스 사전
  • 바인딩
  • 을 : 드디어 두 가지 주요 문제로 내려왔다. 10 개 수백만 GetValue하고있는 ResourceDictionary에 GetValueWithoutLock에 전화처럼 내 경우

    , 내 DataGrids가 포함 된 ItemsControl에서 하나의 논리적 스크롤, 나는 무언가를 얻고 있었다. 처리하는 데 1 초 이상 걸립니다.

    • 동적 자원 검색 : 당신이 ControlTemplates 있고, 더 일반적으로 일부 리소스 사전에 배치 자원을, 당신은 {DynamicResource ...}을 통해 그들에 액세스하는 경우,이를 제거

      ResourceDictionary 접근이 주 번호는 서로 다른 소스에 의해 발생 된 . 어딘가에 정전기가있어 직접 잡으십시오.

    • 스타일 가져 오기 : 사용하는 다른 Visual에 스타일이 없거나 스타일이 있지만 FrameworkElement.OverridesDefaultStyle 속성을 설정하지 않은 경우 WPF는 모든 리소스에서 컨트롤과 일치하는 스타일을 찾으려고 시도합니다. 리소스 사전에 대한 액세스가 많습니다. 이를 방지하려면 컨트롤의 모든 컨트롤 템플릿을 재정의하고 각 컨트롤에 Style={x:Null}을 설정하십시오 (컨트롤 스타일을 필요로하는 경우 컨트롤에 인라인으로 설정하고 OverridesDefaultStyle = true을 추가하십시오)
    • 암시 적 DataTemplates : 암시 적 데이터 템플릿은 매우 유용하지만 무료입니다. 적용 할 DataTemplate을 찾을 때 WPF는 리소스 사전을 다시 검색하여 ViewModels 유형과 일치하는 DataTemplate을 찾습니다. 해결 방법은 ViewModel에 바인드 된 모든 컨트롤에 DataTemplate 선택기를 사용하고 올바른 DataTemplate을 검색하는 최적화 된 방법을 구현하는 것입니다. (나는 개인적으로 resourceDictionary에서 한 번만 검색 한 내 dataTemplate에 대한 정적 필드가 있고 필요에 따라 최적화 된 DataTemplateSelector을 반환합니다.)

    바인딩

    바인딩은 매우 유용하지만, 아주 비싼, 현명 메모리 현명하고 성능을 제공합니다. 퍼포먼스 측면에서 볼 때 매우 합리적인 환경에서, 당신은주의를 기울이지 않고 사용할 수 없습니다. 예를 들어 바인딩은 바인드 된 각 객체에 대해 최대 3 개의 WeakReference를 생성하고 반사 등을 사용할 수 있습니다. 결국 DataContext의 PropertyChanged 이벤트에서 거의 모든 바인딩 및 플러그 된 이벤트 핸들러를 제거하는 것으로 끝 맺었습니다. DataContext이 내 컨트롤 (사용자가 DataContextChanged 이벤트)을 변경하면 DataContextINotifyPropertyChanged을 지원하는지 테스트하고,이 경우 PropertyChanged 이벤트에 이벤트 핸들러를 연결하고 필요에 따라 속성을 업데이트합니다. (나는 단방향 바인딩 만 가지고 있었기 때문에 이것을하는 방식을 선택했다. 그러나 다른 해결책이있다.)

    MVVM과 WPF를 사용할 때 바인딩을 사용하지 않아서 실망 스러울 수도 있지만 실제로는 내 바인딩을 최적화 할 방법이 없습니다.

    마지막 사항 : 가능하다면 Freezable 개 개체 (예 : 브러쉬)와 같은 개체는 Freeze 개 있습니다.

    코드 최적화에 도움이되는 몇 가지 조언이 있습니다. 프로파일 러가 필요합니다 (실제로 필자가 사용했던 최고의 프로파일 러인 dotTrace를 사용하여 조언합니다). 실제로 일어나는 일을 모니터하고 결과에 따라 적응하십시오.

    행운을 빈다.

+0

자세한 답변을 보내 주셔서 감사합니다. 이미 응용 프로그램에서 개선 할 수있는 몇 가지 사항을 담고 있습니다 (freezables, default style override). 나는 이것을보고 나중에보고 할 것이다. –

+0

물론, 어떻게 진행되는지 알려주세요! 그것은 내 블로그에 성능 게시물을 써야만하기 때문에 실제로 나를 위해 좋은 운동이었다 :) – Sisyphe

+0

우리는 모든 리소스 사전을 많이 가지고 있으며 응용 프로그램은 여전히 ​​매우 빠릅니다.우리가 접근 한 방식은 하나의 리소스 (예 : 스타일, 벡터, 브러쉬 등)에 대해 하나의 리소스 사전을 작성한 다음 각보기에서 필요한 리소스 사전 만 참조합니다. 문제는 가상화되지 않기 때문에 균일 한 그리드 자체입니다. – adminSoftDK

4

동일한 크기가 되려고하는 모든 상자가 확실하면 자신의 UniformGrid 클래스를 만들 수 있고 MeasureOverride을 재정 의하여 하나의 자식 만 측정 할 수 있습니다. 나는 현재 프로젝트에서 같은 크기의 내부 컨트롤을 가진 커다란 UniformGrids로 끝날 수 있었기 때문에 당신의 생각이 나를 흥미롭게 만들었고 나는 그것을 정말로 빨리 시도하기로 결정했다 :

필자는 Petzold의 UniformGridAlmost 클래스를 영감으로 사용했지만 하위 클래스로 사용했다. Panel 대신 UniformGrid이 있어야하므로 Rows 및 Columns 종속성 속성을 복제 할 필요가 없습니다. UniformGrid은 계산 된 행 및 열 수를 파생 클래스에 알리기 위해 표시되지 않으므로 Silverlight's UniformGrid class에서 구현을 빌려 UpdateComputedValues 메서드를 사용했습니다. 내 수업에서

MeasureOverride 그래서이

protected override Size MeasureOverride(Size sizeAvailable) 
    { 
    if (InternalChildren.Count == 0) 
    { 
     return new Size(0, 0); 
    } 

    UpdateComputedValues(); 

    // Calculate a child size based on uniform rows and columns. 
    Size sizeChild = new Size(sizeAvailable.Width/ComputedColumns, 
           sizeAvailable.Height/ComputedRows); 

    // Assume children will measure to at least a comparable size. 
    UIElement child = InternalChildren[0]; 
    child.Measure(sizeChild); 

    double width = Math.Max(width, child.DesiredSize.Width); 
    double height = Math.Max(height, child.DesiredSize.Height); 
    return new Size(ComputedColumns * width, ComputedRows * height); 
    } 

처럼 보이는, 여기 키커, 내가 10000 TextBlocks으로 ItemsControl에 그것을 테스트 할 때, UniformGrid의 나의 버전은하지만 작은만큼 (빨랐다 1 % 미만 - MeasureOverride에 대한 호출이 약 95 % 더 빠름을 확인했습니다.) 그래서 이것은 아마도 도움이되지 않을 것입니다,하지만 나는 내 경험을 공유 할 것이라고 생각했습니다. 귀하의 사례에서 획일적 인 레이아웃을 결정하기 위해 모든 상자를 측정 할 필요가 없다는 귀하의 관찰은 사실이지만, 그 측정은 그것을 허물어 뜨리는 것이 아닙니다. 모든 컨트롤이 아직 그려져 있어야하기 때문에 그럴 것이라고 확신합니다. 그러면 어쨌든 나중에 측정 될 것입니다. 당신은 ResourceDictionary/Binding 제안에서 더 많은 것을 얻을 수 있습니다.

+0

나는이 UniformGridAlmost를 그대로 사용했고, 제 경우에는 표준 uniform 그리드보다 약 3 배 빠릅니다. 따라서 드로잉 시간은 20 초에서 약 7 초로 떨어졌습니다. – adminSoftDK

관련 문제