2016-11-25 35 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の更新を強制しますか?それとも可能にするためにコントロール全体を再設計する必要がありますか?

+0

「vis._itemArea.InvalidateArrange()」または「vis._itemArea.InvalidateVisual()」を呼び出すことはできません。 – Clemens

+0

おそらく、ItemVisualizerプロパティの登録時に 'FrameworkPropertyMetadataOptions.AffectsRender'を設定するだけですか? – Clemens

+0

@Clemens、ItemVisualizerはオブジェクトであり、プロパティではありません。しかし、 'UIElement.InvalidateVisual()'は助けます、なぜ私はそれを見落としたのか分かりません。あなたは答えではなく、コメントとして投稿することができます。 – TecMan

答えて

0

通常ItemCountプロパティの登録にFrameworkPropertyMetadataOptions.AffectsRenderを指定するのに十分であるべきである:

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

それが解決しない場合は、あなたがItemAreaElementにInvalidVisual()を呼び出すことによって再描画を強制することができます:

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

はい、私は 'FrameworkPropertyMetadataOptions.AffectsRender'オプションについて覚えていますが、コードから再描画する必要がありました。私が書いたように、 'UIElement.InvalidateVisual()'は期待通りに作業を行います。 – TecMan

関連する問題