使用 XAML/WPF 实现复杂曲线编辑器的策略 [英] Strategy for implementing a complex curve editor with XAML/WPF

查看:49
本文介绍了使用 XAML/WPF 实现复杂曲线编辑器的策略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个相当复杂的CurveEditor,它必须支持以下通常的要求:

I want to implement a rather complex CurveEditor that has to support the usual requirements like:

  • 可自由缩放和可移动的轴
  • 每个曲线点的不同插值类型(线性、三次、样条)
  • 切线(连接和断开)
  • 通过 Fence 或 Click 选择一个或多个点进行编辑(移动、缩放、删除)
  • 仅显示选定曲线点的手柄和高光

我不想操作实际的 WPF 曲线,而是操作具有键/值/切线集的现有模型,并从我们的实现中对曲线的精确形状进行采样.

I don't want to manipulate actual WPF curves but an existing model with key/value/tangents sets and sample the precise shape of the curve from our implementation.

我已经在实施自定义用户控件和模板方面积累了一些经验.但我想确保,我不会错过任何明显的解决方案.我计划拥有这个通用的 XAML 树:

I already gathered some experience on implementing custom UserControls and Templates. But I want to make sure, I don't miss any apparent solution. I planned to have this general XAML-tree:

  • CurveEditor - 包含所有内容的窗口
    • MainThumb:启用拖动和缩放编辑器范围
    • XAxis : UserControl 在左侧呈现一些比例
    • YAxis : UserControl 在底部呈现一些比例
    • Curves :保持曲线的画布
      • Curve :单个曲线的 UserControl
        • CurveName - 曲线标签
        • CurveLine - DrawingVisual 将通过采样样条函数的内部实现来呈现实际曲线.
        • CurveEditPoints - 包含所有编辑点的画布
          • CurveEditPoint - 单个编辑点的用户控件
            • LeftTangent - 左切线手柄的 UserControl
              • LeftTangentThumb - 用于修改手柄
              • CurveEditor - Window holding all content
                • MainThumb : Enable dragging and scaling the editor range
                • XAxis : UserControl rending some scale on the left side
                • YAxis : UserControl rending some scale on the bottom
                • Curves : Canvas holding the curves
                  • Curve : UserControl for a single curve
                    • CurveName - Label of the curve
                    • CurveLine - DrawingVisual that will render the actual curve by sampling the internal implementation of the spline function.
                    • CurveEditPoints - Canvas that holds all edit points
                      • CurveEditPoint - UserControl for a single edit point
                        • LeftTangent - UserControl for the left tangent handle
                          • LeftTangentThumb - For modifying the handle
                          • RightTangentThumb - 用于修改手柄
                          • RightTangentThumb - For modifying the handle
                          • CurvePointThumb - 用拇指选择和拖动点
                          • CurvePointThumb - Thumb to select and drag point around

                          我知道,这是一个相当复杂的问题,我并不要求实际实施.我对以下问题感兴趣:

                          I know, this is quite a complex question and I am not asking for an actual implementation. I am interested in the following questions:

                          1. 你能推荐任何可能对我有帮助的教程或书籍吗(我已经有了 Illustrated WPF、WPF Control Development Unleashed 和其他一些)
                          2. 像切线这样的次要元素应该是单独的用户控件吗?
                          3. 哪种容器最适合托管各个曲线"、编辑点"和切线".现在,我使用 Canvas 和 Canvas.SetLeft/SetTop 来定位孩子,但这感觉很奇怪".
                          4. 我是否应该使用形状"(例如 Path 或 DrawingVisual-Classes)来实现实际表示.Path 很简单,但我担心数百个 CurvePoints 的性能.
                          5. 我应该使用变换来旋转切线还是在文件背后的代码中进行一些三角剖分计算就可以了?
                          6. 该结构是否大致合理,或者您是否建议采用完全不同的方法?

                          推荐答案

                          1. 您似乎手头有合适的工具,WPF Unleashed 非常棒,但我想你已经有了.

                          1. you seem to have the right tools at hand, WPF Unleashed is excellent, but I guess you have that one already.

                          在其中一种情况下制作单独的 UserControl:

                          make individual UserControls in one of these cases:

                          • 您到处都在使用相同的 xaml (DRY)
                          • 您的 xaml 文件太大(取出一些组件)
                          • 需要从某个类继承
                          • you are using the same xaml all over the place (DRY)
                          • you xaml file gets too big (get some components out)
                          • you need to inherit from some class

                          这取决于您想要多少代码隐藏.
                          正如您在评论中所建议的那样,您可以将 ItemsControl 用作需要在多个项目之间进行选择的任何位置的容器.所以这也可以在曲线的水平上完成,而不仅仅是在曲线上的点的水平上.根据您希望如何处理实际线条和曲线的绘制,您甚至可以为它们设置一个 ItemsControl.(附带说明:不过,您将无法开箱即用虚拟化,因为您的项目不会具有恒定的高度)

                          this depends on how much codebehind you want.
                          you can, as you suggested in your comment, use an ItemsControl as a container for wherever you need selection between multiple items. so this could also be done on the level of Curves, not just on the level of points on the curve. Depending on how you want to handle drawing of the actual lines and curves you can even have an ItemsControl for those. (on a side note: you will not have virtualization out of the box though, as your items won't have a constant height)

                          首先使用MVVM.

                          • 曲线编辑器
                            ListBox(Panel=Canvas)(ItemsSource=Curves)(ItemTemplate=CurveControl)

                          • CurveEditor
                            ListBox(Panel=Canvas)(ItemsSource=Curves)(ItemTemplate=CurveControl)

                          曲线控制

                          • Canvas(Background=Transparent) <= 我不确定标准是否为白色,但您不想与其他曲线重叠...
                            • 曲线名称
                            • ListBox(Panel=Canvas(Background=Transparent))(ItemsSource=CurveParts)
                            • ListBox(Panel=Canvas(Background=Transparent))(ItemsSource=CurvePoints)(ItemTemplate=>EditPointControl)

                            EditPointControl

                            EditPointControl

                            • 画布
                              • Thumb(Template = Ellipse) (Name=CenterHandle)(带有一些用于选择和隐藏切线的视觉状态)
                              • 拇指(模板 = 椭圆)(名称 = 左手柄)
                              • 拇指(模板 = 椭圆)(名称 = RightHandle)
                              • 线(将 X/Y 绑定到 Centerpoint 和 LeftHandlePoint)
                              • 线(将 X/Y 绑定到中心点和 RightHandlePoint)

                              我已经声明要为 ListBox 设置 ItemTemplate.但是,您可以根据需要设置列表框的样式(我认为标准样式包括边框,您可能希望删除它或设置 bordersize=0)并设置 ItemContainerStyle 并绑定到 IsSelected 以便您可以从 ViewModel 控制 IsSelected(看 这里 是我的意思.

                              I have stated to set ItemTemplate for the ListBox. You can however style the listbox however you want (I think the standard style includes a border, you might want to remove that or set bordersize=0) and set instead of ItemTemplate the ItemContainerStyle and bind to IsSelected so you have control over IsSelected from your ViewModel (look here for what I mean).

                              所以视图模型看起来像这样:

                              So the viewmodel looks like this:

                              - CurveEditorViewModel
                                  - ObservableCollection<CurveViewModel> Curves
                              
                              
                              - CurveViewModel
                                  - string Label
                                  - (Point LabelPlacement)
                                  - bool IsSelected
                                  - ObservableCollection<CurvePointViewModel> CurvePoints
                                  - ObservableCollection<CurvePartViewModel> CurveParts
                              
                              
                              - CurvePointViewModel
                                  - Point Position
                                  - bool IsSelected
                                  - Point LeftHandle
                                  - Point RightHandle
                              
                              - CurvePartViewModel
                                  - CurvePointViewModel StartPoint
                                  - CurvePointViewModel EndPoint
                                  - Path CurvePath
                              

                              在这里你可以订阅CurvePointViewModel的PropertyChanged并重新计算你暴露的路径.

                              in here you can subscribe to CurvePointViewModel's PropertyChanged and recalculate the Path you're exposing.

                              我可能会改进它,但这是我的第一个猜测.

                              I'd probably improve on it as I go but that'd be my first guess.

                              您可能需要注意一些细节.例如:拇指的样式可能是中间一个可见的圆圈和一个不可见的更大的圆圈,背景=透明.这样你就可以让你的可见圆圈变小,但让用户在小圆圈周围的区域使用 tumb.

                              There are some details you might want to watch out for. eg: the style for the thumbs might be a visible circle in the middle and an invisible bigger one around that with background=transparent. that way you can have your visible circle small, but have the user use the tumb in an area around the small circle.

                              编辑:

                              这是一个拇指示例:

                                      <Thumb Width="8" Height="8" Cursor="Hand" Margin="-4">
                                          <Thumb.Template>
                                              <ControlTemplate TargetType="Thumb">
                                                  <Grid>
                                                      <Ellipse Fill="Transparent" Margin="-6"/>
                                                      <Ellipse Stroke="Red" StrokeThickness="2"/>
                                                  </Grid>
                                              </ControlTemplate>
                                          </Thumb.Template>
                                      </Thumb>
                              

                              因为您想将其定位在画布上的特定点,将边距设置为宽度和高度的减半将使圆的中心位于该点上.此外,使用透明填充的内部椭圆和 -6 的边距,您将在可以拖动拇指的内部(较小)圆圈周围获得 6px 更大的半径.

                              as you want to position this at a specific point on a canvas setting the Margin to minus half the width and height will place the center of the circle on that point. Furthermore, having that inner ellipse with a transparent fill and Margin of -6 you will get a 6px bigger radius around the inner (smaller) circle where you can drag the thumb.

                              这篇关于使用 XAML/WPF 实现复杂曲线编辑器的策略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆