【发布时间】:2011-01-04 19:58:06
【问题描述】:
我想了解 WPF/Silverlight 布局的一般要求,以便实现平移和缩放(拖动和缩放)功能。我指的不是图像的平移和缩放,而是带有一些控件的整个页面(窗口)布局(或其中的一部分)。
布局的哪些功能以及使用的自定义控件的哪些功能使布局无法固定和平移和缩放?
【问题讨论】:
标签: wpf silverlight graphics layout zooming
我想了解 WPF/Silverlight 布局的一般要求,以便实现平移和缩放(拖动和缩放)功能。我指的不是图像的平移和缩放,而是带有一些控件的整个页面(窗口)布局(或其中的一部分)。
布局的哪些功能以及使用的自定义控件的哪些功能使布局无法固定和平移和缩放?
【问题讨论】:
标签: wpf silverlight graphics layout zooming
一般规则
除了少数例外,WPF 中的所有内容都可以随心所欲地平移、缩放、旋转、拉伸等。这包括像 Button 这样的单个控件、像 ListBox 这样的复合控件以及像 StackPanel 这样的容器。
例外情况
以下是例外情况:
如果您正在使用 Adorner,并且您的 AdornerDecorator 位于平移/缩放区域之外,则附加到您的平移/缩放区域的 Adorner 将平移但不会缩放。解决方案是在平移/缩放区域内放置一个额外的 AdornerDecorator。
如果您使用 Popup,它将显示在其 PlacementTarget 的平移/缩放位置,但它本身不会被缩放。当您平移包含其 PlacementTarget 的区域时,它也不会移动(基本上它位于目标控件上方的自己的表面中)。为了解决这个问题,当您希望在缩放/平移区域内弹出某些内容时,请使用具有高 Z 顺序的零尺寸 Canvas。
您定义的任何 ContextMenu 都将显示在弹出窗口中,因此即使您单击的区域被放大或缩小,菜单项也将显示正常大小。由于上下文菜单的性质,这可能是理想的行为。如果没有,您可以将菜单项包装在 ViewBox 中,并将缩放与主区域的缩放联系起来。
即使 UI 被平移或缩放,您的工具提示也会显示正常大小。与 ContextMenu 相同的解决方案。
如果您使用 WinForms 集成来集成旧版 WinForms 控件和 UI,它们在某些情况下将无法正确平移、缩放和剪辑。有一种解决此问题的高级技术,您可以在屏幕外实现 WinForms 控件,然后使用 BitBlt 或类似方法将图像作为图像复制到您的窗口中,然后将鼠标单击和击键转发到屏幕外窗口。不过,这是很多工作。
如果您绕过 WPF 并直接使用 GDI+ 或 DirectX,或使用 Win32 hWnds 显示内容或 UI,除非您自己在您的接口代码。
结语
一个好的 WPF UI 总是使用 Grid、DockPanel 等面板以灵活的方式布局控件,以便它们自动调整到容器大小,而不是使用固定的大小和位置。对于平移/缩放区域的内部内容也是如此,但此规则有一个例外:平移/缩放区域中最外层的元素必须具有指定的大小。否则什么会定义被平移/缩放的区域?
实现平移/缩放功能的简单方法是调整平移/缩放区域中最外层控件的 RenderTransform。有许多不同的方法来实现平移和缩放控件,例如,您可以使用工具栏按钮和滑块、滚动条、鼠标滚轮、空格键+拖动来平移、平移 UI 本身的可拖动区域或这些的任意组合。无论您选择哪种接口,只要让它从代码隐藏中适当地更新 RenderTransform 就可以了。
如果您选择的平移机制是滚动条,您可能希望使用 ScrollViewer 并且仅使用 RenderTransform 进行缩放。
确保在平移/缩放区域设置剪辑。否则,如果您放大或平移项目,它们在平移/缩放区域之外仍然可见。
【讨论】:
"There is an advanced technique for working around this, where you implement the WinForms control off-screen, then using BitBlt or similar copy the image into your window as an image, and forward mouse clicks and keystrokes to the offscreen window. This is a lot of work, though." 你有做过这件事的人的推荐信吗?特别是事件转发机制似乎很棘手。
一般来说,您可以像对待单个 UIElement 一样对待任何组合的 UI 元素集,因此图像的情况与对整个应用程序进行相同的情况并没有真正的不同。处理基于用户输入的缩放(与 Viewbox 所做的自动缩放相反)的最佳方法是应用 ScaleTransform。这可以设置在高级父元素上,例如 Window 布局根部的 Grid。对于平移,您可以在 TranslateTransform 中组合使用,或者在某些情况下使用 ScrollViewer 来处理内容视图的移动。
【讨论】:
在 XAML 中实现缩放的一种非常简单的方法是使用 Silverlight ViewBox。这会缩放 XAML 而不是像素。您可以指定要使用的拉伸,ViewBox 将基于此缩放(填充、无、均匀等)。如果您在 Google 上搜索 Silverlight+Viewbox,可以在网络上找到一些很棒的 Viewbox 博客文章。
使用与拖放类似的机制可以轻松完成平移,还有许多关于此的操作方法博客文章,可通过 Google 获得。仅相当于捕获 MouseDown、MouseMove 和 MouseUp 事件。
【讨论】: