2016-11-25 13 views
0

사용자 지정 WPF 컨트롤에서 작업하고 있습니다. 이 컨트롤의 주 목적은 스크롤 가능한 영역에 수천 개의 그래픽 프리미티브를 시각화하는 것입니다. 컨트롤 템플릿의 핵심 부분은 다음과 같습니다.사용자 지정 WPF 컨트롤에서 사용자 지정 UIElement 그리기를 강제로 다시 적용

<Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="{x:Type local:ItemVisualizer}"> 
      <Border Background="{TemplateBinding Background}" 
        BorderBrush="{TemplateBinding BorderBrush}" 
        BorderThickness="{TemplateBinding BorderThickness}"> 

       <Grid> 
        <Grid.RowDefinitions> 
         <RowDefinition Height="*" /> 
         <RowDefinition Height="Auto" /> 
        </Grid.RowDefinitions> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*" /> 
         <ColumnDefinition Width="Auto" /> 
        </Grid.ColumnDefinitions> 
        <local:ItemAreaElement Grid.Row="0" Grid.Column="0" x:Name="PART_ItemArea" /> 
        <ScrollBar Grid.Row="0" Grid.Column="1" x:Name="PART_ScrollBarVert" Orientation="Vertical" Maximum="100" /> 
        <ScrollBar Grid.Row="1" Grid.Column="0" x:Name="PART_ScrollBarHorz" Orientation="Horizontal" Maximum="100" /> 
        <Rectangle Grid.Row="1" Grid.Column="1" x:Name="PART_SizeGrip" Focusable="False" Fill="#F0F0F0" /> 
       </Grid> 

      </Border> 
     </ControlTemplate> 
    </Setter.Value> 
</Setter> 

ItemAreaElement는 항목 그리기를 담당합니다. 단순화하기 위해, 우리는 핵심 부분은 다음과 같다라고 생각 할 수 있습니다

class ItemAreaElement : FrameworkElement 
{ 
    protected override void OnRender(DrawingContext drawingContext) 
    { 
     base.OnRender(drawingContext); 

     for (int i = 0; i < _data.ItemCount; i++) 
     { 
      drawingContext.DrawLine(_penLine, new Point(0, i * 10), new Point(100, i * 10)); 
     } 
    } 
} 

내가 ItemAreaElement 때마다 다시 칠해야하는 경우 전체 ItemVisualizer 제어 변경에 관련된 속성입니다. 그러나 WPF에서 그렇게하는 방법을 찾지 못했습니다. 디스패처 객체 잘 알고 트릭은 내 경우에는 작동하지 않습니다 _itemArea가 ItemAreaElement의 로컬 참조입니다

private static void OnItemCountPropertyChanged(DependencyObject source, 
     DependencyPropertyChangedEventArgs e) 
{ 
    ItemVisualizer vis = (ItemVisualizer)source; 
    vis._itemArea.Dispatcher.Invoke(delegate { }, DispatcherPriority.Render); 
} 

는 OnApplyTemplate()에 있어요 :

public override void OnApplyTemplate() 
{ 
    base.OnApplyTemplate(); 

    if (this.Template != null) 
    { 
     _itemArea = this.Template.FindName("PART_ItemArea", this) as ItemAreaElement; 
     _itemArea.Grid = this; 
    } 
} 

는 다른 방법이있다 내 구성에서 UIElement의 업데이트를 강제 실행 하시겠습니까? 아니면 가능하도록 전체 컨트롤을 다시 디자인해야합니까? ItemAreaElement에 InvalidVisual()를 호출하여 그 문제가 해결되지 않으면

public static readonly DependencyProperty ItemCountProperty = 
    DependencyProperty.Register(
     "ItemCount", typeof(int), typeof(ItemVisualizer), 
     new FrameworkPropertyMetadata(FrameworkPropertyMetadataOptions.AffectsRender)); 

, 당신은 다시 그리기를 강제 수 :

+0

'vis._itemArea.InvalidateArrange()'또는 'vis._itemArea.InvalidateVisual()'을 호출 할 수 없습니까? – Clemens

+0

아니면 ItemVisualizer 속성을 등록 할 때'FrameworkPropertyMetadataOptions.AffectsRender'를 설정해야할까요? – Clemens

+0

@Clemens, ItemVisualizer는 속성이 아니라 객체입니다. 하지만 UIElement.InvalidateVisual()은 도움이됩니다. 왜 내가 간과했는지 모르겠습니다. 답변으로 답변을 게시 할 수 있습니다. – TecMan

답변

0

일반적으로 ItemCount 재산의 등록에 FrameworkPropertyMetadataOptions.AffectsRender을 지정하는 데 충분해야한다

var vis = (ItemVisualizer)source; 
vis._itemArea.InvalidVisual(); 
+0

예,'FrameworkPropertyMetadataOptions.AffectsRender' 옵션에 대해 기억하지만, 코드에서 다시 칠할 필요가있었습니다. 내가 쓴 것처럼,'UIElement.InvalidateVisual()'은 예상대로 작업을 수행합니다. – TecMan