0

カスタム WPF コントロールに取り組んでいます。このコントロールの主な目的は、スクロール可能な領域で何千ものグラフィック プリミティブを視覚化することです。コントロールのテンプレートのコア部分は次のようになります。

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

ItemVisualizer コントロール全体の関連プロパティが変更されるたびに、ItemAreaElement を再描画する必要があります。しかし、WPF でそれを行う方法が見つかりませんでした。私の場合、 Dispatcher オブジェクトを使用したよく知られたトリックは機能しません。

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

ここで、_itemArea は OnApplyTemplate() で取得した ItemAreaElement へのローカル参照です。

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

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

私の構築で UIElement の更新を強制する他の方法はありますか? それとも、それを可能にするためにコントロール全体を再設計する必要がありますか?

4

1 に答える 1

0

通常、プロパティFrameworkPropertyMetadataOptions.AffectsRenderの登録時に指定するだけで十分です。ItemCount

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

それでも解決しない場合はInvalidVisual()、ItemAreaElement を呼び出して強制的に再描画できます。

var vis = (ItemVisualizer)source;
vis._itemArea.InvalidVisual();
于 2016-11-25T12:59:59.303 に答える