需要将文本块添加到组框并在图形控件中加载数据时清除

发布于 2024-08-11 06:07:33 字数 274 浏览 9 评论 0原文

我正在创建一个图形控件。我正在做的添加 x 和 y 轴计数标签的操作是 将文本块添加到每个计数标记并显示与该计数标记相关的值。

但是当我需要从数据库加载数据并再次重新绘制文本块并刷新图形区域时,我无法删除旧的文本块,它们仍然位于图形窗格上。

为了克服这个问题,我想将文本块放在组框旁边,当重新绘制图形窗格以删除组框元素并再次放置它们时。

这种方法正确吗? 请告诉我如何在类后面的代码中将元素放入组框中? 请告诉我他们是否有其他解决方案来解决我的问题。

问候, 兰加纳。

I'm creating a graph control. what i'm doing for adding x and y axis tally labels is i'm
adding a text block to each tally mark and show the value related to that tally mark.

but when i need to load data form the database and redraw the textbolcks again and refresh the graph area i can't remove the older textblocks they are still on the graph pane.

to overcome this problem i thought to put the text blocks in side a group box and when graph pane is redrawn to delete the group box elements and put them again..

is this approach correct?
please tell me how to put elements to groupbox in code behind class?
and please tell me if their is any other solution to my problem.

regards,
rangana.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦里人 2024-08-18 06:07:33

在 WPF 中,大多数问题都有多种解决方案。我将讨论解决您的问题的三种可能的解决方案 - 您描述的一个和其他两个。您可以决定哪一个最适合您。

解决方案 1:使用 TextBlock 对象显示标签

听起来您有一个 Canvas,并且为每个刻度添加一个 TextBlock标记。如果性能不是太重要并且您不能使用数据绑定,那么这是一个可行的解决方案。

在这种情况下,有两种方法可以删除 TextBlock:

  1. 您可以保留一个 List,其中包含上次创建标签时创建的 TextBlock 的所有 Textblocks 列表。每当您重新创建标签时,请运行此列表并从包含面板(画布)中删除列表上的每个 TextBlock

  2. 您可以创建一个新的 Canvas 并将 TextBlock 放在其上,然后在重新标记时删除整个 Canvas。

下面是第二种技术的示例,因为它的效率稍高一些:

class MyGraphBuilder
{
  Canvas _labelCanvas;
  ...
  void AddLabels()
  {
    // Remove old label canvas, if any
    if(_labelCanvas!=null)
      _graphCanvas.Children.Remove(_labelCanvas);

    // Add new label canvas
    _labelCanvas = new Canvas();
    _graphCanvas.Children.Add(_labelCanvas);

    // Create labels
    foreach(...)
    {
      ...
      _labelCanvas.Add(new TextBlock ...
    }
    ...

  }
}

解决方案 2:使用数据绑定

在 WPF 中,您无需编写一行代码即可创建许多图表! WPF 内置的数据绑定足以创建相对复杂的条形图等。

下面是使用数据绑定创建简单条形图的示例:

<ItemsControl ItemsSource="{Binding myData}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <DockPanel>
        <TextBlock Width="50" Text="{Binding Label}"/>
        <Rectangle VerticalAlignment="{Stretch}" Width="{Binding Value}">
          <Rectangle.LayoutTransform>
            <ScaleTransform ScaleX="10" /> <!-- Scale factor here, can be binding too -->
          </Rectangle.LayoutTransform>
        </Rectangle>
        <TextBlock Text="{Binding Value}" FontSize="8"/>
      </DockPanel>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

可以通过使用水平布置的第二个 ItemsControl 将数字标签添加到水平轴,并且其数据模板具有固定宽度并显示数字和刻度线。

解决方案 3:使用低级绘图类

通过构造 DrawingGroup 对象并添加 GeometryDrawingGlyphRunDrawing 对象来构建图形到它,然后将 DrawingGroup 放入 DrawingVisual 中,并将其添加到您的主 Panel 中。

对于共享给定画笔和笔的每组项目,您应该使用一个 GeometryDrawingGlyphRunDrawing。例如,如果您的轴和刻度线的颜色和宽度都相同,则为所有轴和刻度线创建一个 GeometryDrawing,但如果每个刻度线颜色不同,则创建多个 GeometryDrawing代码>对象。

您将为每个GeometryDrawing 创建一个Geometry 对象。为了获得最佳效率,它应该是 StreamGeometry,但其他 Geometry 类也可以很好地工作,可能更易于使用,并且可以在 XAML 中初始化。您可能已经熟悉创建 PathGeometryEllipseGeometry,因此我将重点介绍创建 StreamGeometry。您可以通过在 using() 语句中调用 Open 方法,然后写入返回的上下文来完成此操作。下面是一个示例:

Geometry BuildAxesAndTicksGeometry()
{
  // First create geometry
  var geometry = new StreamGeometry();
  using(var context = geometry.Open())
  {
    // Horizontal axis
    context.BeginFigure(new Point(0,0), false, false);
    context.LineTo(new Point(_width, 0), true, false);

    // Vertical axis
    context.BeginFigure(new Point(0,0), false, false);
    context.LineTo(new Point(0, _height), true, false);

    // Horizontal ticks
    for(int i=0; i<_nTicksHorizontal; i++)
    {
      context.BeginFiture(new Point(i * _tickSpacing, -10), false, false);
      context.LineTo(new Point(i * _tickSpacing, 10), true, false);
    }
    // Do same for vertical ticks
  }

  // Now add it to a drawing
  return new GeometryDrawing { Geometry = geometry, Stroke = _axisPen };
}

Drawing BuildDrawing()
{
  var mainDrawing = new DrawingGroup();
  mainDrawing.Add(BuildAxesAndTicksGeometry());
  ... // Add other drawings, including one or more for the data
  return mainDrawing;
}

void UpdateDrawing()
{
  myDrawingVisual.Drawing = BuildDrawing();  // where myDrawingVisual is defined in the XAML
}

解决方案比较

对于大多数情况,我会推荐解决方案 2 或 3,原因如下:

  • 如果图形足够简单,可以使用数据绑定,那么它将为您节省大量时间。采用解决方案 2。
  • 如果图形无法通过数据绑定完成,则使用 Drawing 对象大约与任何其他技术一样简单,并且可以执行得更好。采用解决方案 3。

在您的情况下,如果您已经在解决方案 1 中投入了大量工作,那么您可能希望坚持使用它,即使它可能不是最好的。

In WPF there are many solutions to most problems. I will discuss three possible solutions to your problem - the one you describe and two others. You can decide which will work best for you.

Solution 1: Using TextBlock objects to disply the labels

It sounds like you have a Canvas and you're adding a TextBlock to it for each tick mark. This is a viable solution if performance isn't too critical and you can't use data binding.

There are two ways to remove the TextBlocks in this case:

  1. You can keep a List<TextBlock> containing all the Textblocks list of the TextBlocks you created the last time you created the labels. Whenever you recreate the labels, run through this list and remove each TextBlock on the list from the containing panel (the Canvas)

  2. You can create a new Canvas and put the TextBlocks on it, then delete the whole Canvas when you relabel.

Here is an example of the second technique, since it is slightly more efficient:

class MyGraphBuilder
{
  Canvas _labelCanvas;
  ...
  void AddLabels()
  {
    // Remove old label canvas, if any
    if(_labelCanvas!=null)
      _graphCanvas.Children.Remove(_labelCanvas);

    // Add new label canvas
    _labelCanvas = new Canvas();
    _graphCanvas.Children.Add(_labelCanvas);

    // Create labels
    foreach(...)
    {
      ...
      _labelCanvas.Add(new TextBlock ...
    }
    ...

  }
}

Solution 2: Using data binding

In WPF you can create many graphs without writing a single line of code! WPF's built in data binding is sufficient to create relatively complex bar charts, etc.

Here is an example of using data binding to create a simple bar chart:

<ItemsControl ItemsSource="{Binding myData}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <DockPanel>
        <TextBlock Width="50" Text="{Binding Label}"/>
        <Rectangle VerticalAlignment="{Stretch}" Width="{Binding Value}">
          <Rectangle.LayoutTransform>
            <ScaleTransform ScaleX="10" /> <!-- Scale factor here, can be binding too -->
          </Rectangle.LayoutTransform>
        </Rectangle>
        <TextBlock Text="{Binding Value}" FontSize="8"/>
      </DockPanel>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

Numeric labels can be added to the horizontal axis by using a second ItemsControl laid out horizontally, and with its data template a fixed width and showing numbers and tick marks.

Solution 3: Using low level Drawing classes

Build your graph by constructing a DrawingGroup object and adding GeometryDrawing and GlyphRunDrawing objects to it, then putting the DrawingGroup inside DrawingVisual and add that to your main Panel.

You should use one GeometryDrawing or GlyphRunDrawing for each set of items sharing a given brush and pen. For example if your axes and tick marks are all the same color and width, create a single GeometryDrawing for all of them, but if each tick mark is a differnet color, create multiple GeometryDrawing objects.

You will create a Geometry object for each GeometryDrawing. For the best efficiency it should be a StreamGeometry, but the other Geometry classes also work well, may be easier to use, and may be initialized in XAML. Creating a PathGeometry or EllipseGeometry is probably already familar to you so I'll focus on creating a StreamGeometry. You do this by calling the Open method in a using() statement, then writing to the returned context. Here is an example:

Geometry BuildAxesAndTicksGeometry()
{
  // First create geometry
  var geometry = new StreamGeometry();
  using(var context = geometry.Open())
  {
    // Horizontal axis
    context.BeginFigure(new Point(0,0), false, false);
    context.LineTo(new Point(_width, 0), true, false);

    // Vertical axis
    context.BeginFigure(new Point(0,0), false, false);
    context.LineTo(new Point(0, _height), true, false);

    // Horizontal ticks
    for(int i=0; i<_nTicksHorizontal; i++)
    {
      context.BeginFiture(new Point(i * _tickSpacing, -10), false, false);
      context.LineTo(new Point(i * _tickSpacing, 10), true, false);
    }
    // Do same for vertical ticks
  }

  // Now add it to a drawing
  return new GeometryDrawing { Geometry = geometry, Stroke = _axisPen };
}

Drawing BuildDrawing()
{
  var mainDrawing = new DrawingGroup();
  mainDrawing.Add(BuildAxesAndTicksGeometry());
  ... // Add other drawings, including one or more for the data
  return mainDrawing;
}

void UpdateDrawing()
{
  myDrawingVisual.Drawing = BuildDrawing();  // where myDrawingVisual is defined in the XAML
}

Comparison of solutions

For most cases I would recommend solution 2 or 3, for these reasons:

  • If the graph is simple enough to use data binding it will save you a lot of time. Go with solution 2.
  • If the graph cannot be done with data binding, using Drawing objects is approximately as simple as any other technique, and can perform better. Go with solution 3.

In your case if you've already invested significant work into your Solution 1, you may want to stick with it even though it probably isn't the best.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文