2011-06-13 96 views
2

我最近为我的公司开发了一个绘图组件,其中包含一个Canvas,通过它可以使用点击拖动来绘制某些形状。对于每一个形状,我在它的AdornerLayer上放置了两个装饰物:一个用于增加命中检测(基本上是一个透明的矩形,它将超出形状的边界几个像素),另一个用于调整大小(角落上的四个拇指控制)。WPF装饰者有什么意义?

但是,当执行组件的一些功能时,我遇到了很多问题,所有与装修有关的问题。

  • 他们将所有预览事件,因为他们是在另一可视化树比画布本身,那是意外,但我找到了一个解决办法,即使我不喜欢那么多。使用AdornerDecorator并没有解决这个问题,我实施的选择装饰者是预览事件的黑洞。当我对Canvas上的形状执行z-index操作(发送回来,到达前面等)时,它可以正常使用Panel.SetZIndex,正如你所期望的那样。但是,装饰者在另一个视觉树上!所以他们没有受到影响,而选择装饰师仍然在所有其他形状之上,即使这些形状在选择装饰者正在检测到的形状之上。例如: Shape1,SelectionAdorner1。 Shape2,SelectionAdorner2。 Shape1位于Shape2的顶部(稍后添加到画布上),因此它与其重叠。因此点击它将被SelectionAdorner1检测到。我操纵ZIndex将其发回,现在Shape2位于顶部并与Shape1重叠。我点击Shape2的顶部,但点击是由SelectionAdorner1而不是SelectionAdorner2检测到的。 这特别烦人。所以,显然自Adorners在另一个视觉树上,他们不尊重ZIndexes。我试图通过在形状的ZIndex和它的SelectionAdorner的ZIndex之间创建一个DataBinding(并且通过手动设置)来解决它。但是这并没有解决问题。改变Adorners的ZIndex并不影响它们在屏幕上的显示方式,也许我错过了一些东西,但它不应该真的这么难,因为Adorners应该是为了让事情变得更容易。我能想出的唯一解决方案是手动删除所有装饰者,然后再一次手动添加它们,最后添加应该位于最上面的装饰者。这是迟缓的,但它的工作。

  • 接下来,装饰者不尊重ClipToBounds!我在Canvas中设置了ClipToBounds = true我正在做绘图,它运行良好,但该死的装饰者仍然会工作!对此的解决方案是相对无痛的,我只是在每个Shape的顶部添加了一个AdornerDecorator。这不是IMO的理想解决方案,但它足够简单。

  • 装饰者并不总能很好地对其装饰元素上执行的LayoutTransforms做出反应。我有一个实现缩放和平移功能的画布顶部的面板。它使用动画来缩放和平滑。但是使用动画导致我的装饰者变得猿猴!第一次缩放它们会忽略调整大小并保持相同的大小和位置,在第二次缩放时,它们将缩放到以前的大小的装饰元素。这没有任何意义!唯一的解决办法我能找到的禁用动画,这令人欣慰工作

我不太记得它的其他问题我有,但这是绰绰有余MAME我想知道装饰器的用处,我我认真考虑不在下一个项目中使用它们,这与我描述的类似。

那么,谁能告诉我什么可能是使用这些看似有用但令人难以置信的恼人的东西的优点?

谢谢。

回答

6

我认为你已经知道你的问题的答案。它们在某些方面节省时间,并在其他方面造成问题。如果您要使用各种UserControl编写此设计器行为,则会发现自己编写了大量样板控件类来包装您实际想要编辑的元素。另一方面,如果您尝试编写单独的编辑控件并智能地覆盖它们,您将编写样板代码以保持其位置和大小同步。你采用的方法,使用装饰,导致了很多(相当模板)的代码来管理事件。

虽然装饰者可能不是这个特定任务的最佳工具,但它们仍然是其他更简单任务的有用工具。我最近写了一个类似的“设计表面”,装饰品是天赐的两件作品:

  1. 拖放行为。当我拖动不同的元素时,他们需要有不同的视觉预览;使用自定义装饰器和数据模板非常容易实现。
  2. 选择矩形或“套索”。当您在Windows桌面上按住鼠标左键并拖动指针时,可以看到类似的东西。它创建了一个可以选择多个元素的半透明框。我能够几乎立即用装饰图层创建此行为,而创建自己的自定义控件导致了大量不必要的记帐。

我想你在你的项目中发现的是,你可能一直在使用装饰者来尝试和完成太多。但不要把宝宝扔出去洗澡 - 它们在某些情况下仍然非常有用。

+0

你是非常正确的,你可能对我有用的地方的例子很有趣,特别是因为我会需要类似的东西来拖放,谢谢你的提示。 – 2011-06-14 02:24:33