2016-11-25 4 views
0

Je travaille sur un contrôle WPF personnalisé. Le but principal de ce contrôle est de visualiser des milliers de primitives graphiques dans une zone défilante. La partie principale du modèle du contrôle ressemble à ceci:Forcer la repeinte d'un UIElement personnalisé dans un contrôle WPF personnalisé

<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> 

La propriété ItemAreaElement est responsable du dessin des éléments. Pour simplifier, on peut penser que sa partie de base ressemble à ceci:

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)); 
     } 
    } 
} 

J'ai besoin de repeindre le ItemAreaElement chaque fois une propriété liée à l'ensemble des changements de contrôle ItemVisualizer. Cependant, je n'ai pas trouvé un moyen de le faire dans WPF. Le bien savoir truc avec l'objet Dispatcher ne fonctionne pas dans mon cas:

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

, où _itemArea est une référence locale à l'ItemAreaElement obtenu dans OnApplyTemplate():

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

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

Y at-il d'autres façons de forcer une mise à jour de l'UIElement dans ma construction? Ou peut-être, je dois redessiner tout le contrôle pour le rendre possible?

+0

Vous ne pouvez pas simplement appeler 'vis._itemArea.InvalidateArrange()' ou 'vis._itemArea.InvalidateVisual()'? – Clemens

+0

Ou probablement juste définir 'FrameworkPropertyMetadataOptions.AffectsRender' sur l'enregistrement de la propriété ItemVisualizer? – Clemens

+0

@Clemens, ItemVisualizer est un objet, pas une propriété. Mais 'UIElement.InvalidateVisual()' aide, je ne sais pas pourquoi je l'ai négligé. Vous pouvez poster ceci comme une réponse, pas un commentaire. – TecMan

Répondre

0

Il devrait normalement être suffisant pour indiquer FrameworkPropertyMetadataOptions.AffectsRender sur l'enregistrement de la propriété ItemCount:

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

Si cela ne fonctionne pas, vous pourriez forcer un redessiner en appelant InvalidVisual() sur le ItemAreaElement:

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

Oui, je me souviens de l'option 'FrameworkPropertyMetadataOptions.AffectsRender', mais j'avais besoin de repeindre à partir de mon code. Comme je l'ai écrit, 'UIElement.InvalidateVisual()' fait le travail comme prévu. – TecMan