WPF元素渲染顺序

时间:2017-01-10 03:54:44

标签: c# wpf

背景

我需要一个我正在处理的应用程序的图表系统,并且无法找到能够做我所需要的任何免费的,所以我决定自己编写。

到目前为止的解决方案

我将避免在他的观点中详细介绍设计,但这是XAML代码的示例和结果的屏幕截图。希望这能说明系统(一组自定义WPF控件)的结构。

<Window x:Class="ChartTestApp_1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:charts="clr-namespace:BB.Play.Wpf.Charts;assembly=BB.Play.Wpf.Charts"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="560"
        Background="Black">

  <Window.Resources>
    <ResourceDictionary Source="/BB.PLay.Wpf.Charts;component/Themes/Generic.xaml"/>
  </Window.Resources>

  <Grid>
    <charts:Chart Margin="20" BorderThickness="0">
      <charts:Chart.Axes>
        <!-- The Y axis -->
        <charts:NumericAxis Style="{StaticResource VerticalNumercAxis}"
                            Name="ValueAxis"
                            IsScrollable="True"
                            IsZoomable="True"
                            Minimum="{Binding MinValue}"
                            Maximum="{Binding MaxValue}"
                            Source="Value">
          <charts:Axis.Hatching>
            <charts:LinearHatching Style="{StaticResource MajorVerticalHatching}" IsAuto="True" MinimumSpacing="30"/>
            <charts:LinearHatching Style="{StaticResource MinorVerticalHatching}" IsAuto="True" MinimumSpacing="30"  IsGridLine="True"/>
          </charts:Axis.Hatching>
        </charts:NumericAxis>

        <!-- The X axis -->
        <charts:TimeAxis Style="{StaticResource HorizontalTimeAxis}"
                         Name="TimeAxis"
                         IsPrimaryAxis="True"
                         Minimum="{Binding StartTime}"
                         Maximum="{Binding EndTime}"
                         Source="Time">
          <charts:Axis.Hatching >
            <charts:LinearHatching Style="{StaticResource MinorHorizontalHatching}" IsAuto="True" MinimumSpacing="240" LabelFormat="|dd MMM yy"/>
            <charts:LinearHatching Style="{StaticResource MinorHorizontalHatching}" IsAuto="True" MinimumSpacing="60" LabelFormat=""/>
            <charts:LinearHatching Style="{StaticResource MinorHorizontalHatching}" IsAuto="True" MinimumSpacing="20" IsLabeled="False" IsGridLine="True"/>
          </charts:Axis.Hatching>
        </charts:TimeAxis>
      </charts:Chart.Axes>

      <!-- The main chart area -->
      <charts:Chart.Presenters>

        <!-- The background -->
        <charts:UIPresenter>
          <Grid>
            <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
              <Rectangle.Fill>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                  <GradientStop Color="Black" Offset="0.0" />
                  <GradientStop Color="#000044" Offset="1.0" />
                </LinearGradientBrush>
              </Rectangle.Fill>
            </Rectangle>
            <TextBlock Foreground="SteelBlue" FontSize="14" Margin="5">Chart Test 1</TextBlock>
          </Grid>
        </charts:UIPresenter>

        <!-- The grid lines -->
        <charts:GridLinePresenter SnapsToDevicePixels="True"/>

        <!-- The data -->
        <charts:DataPresenter DataItemsProvider="{Binding DataProvider}"
                              charts:ChartPanel.HorizontalPosition="Center"
                              charts:ChartPanel.VerticalPosition="Center"
                              XAxisName="TimeAxis"
                              YAxisName ="ValueAxis"
                              ClipToBounds="True">
          <charts:DataPresenter.ArtistTemplate>
            <DataTemplate>
              <charts:Artist X="{Binding Time}"
                             Y="{Binding Value}">
                <charts:Artist.Template>
                  <DataTemplate>
                    <Ellipse Height="5" Width="5" Fill="DarkOrange"/>
                  </DataTemplate>
                </charts:Artist.Template>
              </charts:Artist>
            </DataTemplate>
          </charts:DataPresenter.ArtistTemplate>
        </charts:DataPresenter>
      </charts:Chart.Presenters>
    </charts:Chart>
  </Grid>
</Window>

enter image description here

现状

我目前正在为系统提供图表网格线的部分工作。此功能由名为 GridLinePresenter 的控件提供,并包含在XAML底部的 Presenters 中。 由于图表既可滚动又可缩放,我无法使用静态网格线,并且由于网格线与轴上的阴影线对齐,因此使用它们的位置来排列网格线似乎是合乎逻辑的。

部分代码

只要轴滚动或缩放,就会调用以下方法之一。

private void UpdateScrollPosition(Point currentScrollPosition)
{
  var distance = Orientation == PartOrientation.Horizontal
    ? _lastScrollPosition.X - currentScrollPosition.X
    : _lastScrollPosition.Y - currentScrollPosition.Y;
  _lastScrollPosition = currentScrollPosition;
  VisualRange.Move(distance);
  InvalidateAxis();
  RaiseAxisChanged();
}

private void Zoom(double delta)
{
  VisualRange.Zoom(delta / 12.0);
  ScaleRange(DesiredSize);
  InvalidateAxis();
  RaiseAxisChanged();
}

两种方法的最后一行是

RaiseAxisChanged();

这将触发演示者可以订阅的事件(未路由),以便他们可以根据新轴详细信息自行更新。在上面的示例中,这包括GridLinePresenter和DataPresenter,但不包括UIPresenter,因为它不需要更改。在使用它的两种情况下,事件处理程序都是

private void OnAxisMoved(object sender, EventArgs e)
{
  InvalidateMeasure();
}

问题

由于轴的阴影线是在 AxisHatching 控件的 MeasureOverride 中计算的,因此必须处理Axis及其所有子控件在渲染的测量过程之前调用 GridLinePresenter 上的 MeasureOverride ,否则它将最终使用阴影位置的旧值来排列网格线。

即使 Axis GridLinePresenter 之前失效并且在可视树中位于较高位置,但这并不能保证它将首先被处理。实际上目前的订单是

GridLinePresenter.MeasureOverride()

Axis.MeasureOverride()

Axis.ArrangeOverride()

GridLinePresenter.ArrangeOverride()

导致绘制错误数量的网格线(缩放时)或绘制在错误的位置。

问题

首先 - WPF如何确定渲染过程中处理元素的顺序?我认为这可能是他们在视觉树中的位置和/或他们的Z-Index,但事实并非如此。

第二 - 这会受到影响吗

0 个答案:

没有答案