战略实施与XAML / WPF一个复杂的曲线编辑器 [英] Strategy for implementing a complex curve editor with XAML/WPF

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

问题描述

我想实现一个相当复杂的CurveEditor有支持像通常的要求:


  • 自由伸缩和可移动的轴

  • 每个曲线点不同的插补类型(线性,立方,花键)

  • 切线(加入和碎)

  • 选择一个或几个点进行编辑(移动,缩放,删除),通过围栏或点击

  • 仅显示手柄和亮点选定的曲线点

我不想操纵实际WPF曲线,但键/值/切线套现有模型,并从我们的实现采样曲线的precise形状。

我已经收集了有关实现自定义用户控件和模板的一些经验。但我想确保我不会错过任何明显的解决方案。我计划让这个一般XAML树:


  • CurveEditor - 窗口保存所有内容

    • MainThumb :启用拖动和缩放编辑范围

    • XAXIS :用户控件撕心裂肺的一些规模左侧

    • Y轴:用户控件撕心裂肺的一些规模底部

    • 曲线:帆布抱着曲线

      • 曲线:用户控件为一条曲线

        • CurveName - 曲线的标签

        • CurveLine - DrawingVisual将通过采样内部实现的样条函数的渲染实际曲线

        • CurveEditPoints - 帆布保存所有编辑点

          • CurveEditPoint - 用户控件的一个编辑点

            • LeftTangent - 用户控件左手柄相切

              • LeftTangentThumb - 修改手柄


            • RightTangent - 用户控件为右手柄切线

              • RightTangentThumb - 修改手柄



          • CurvePointCenter - 实际点,选择状态和插补类型的可视化。

            • CurvePointThumb - 拇指选择和拖动点左右







我知道,这是一个相当复杂的问题,我不要求实际实现。我感兴趣的是以下几个问题:


  1. 你能不能推荐任何教程或书籍,可能会帮助我(我已经得到了画报WPF,WPF控件开发如虎添翼,和其他几个)

  2. 想的切线微量元素是个别用户控件?

  3. 什么容器是最适合于承载个人曲线,EditPoints和切线。现在,我使用Canvas和Canvas.SetLeft /机顶盒给孩子的位置,但感到奇怪。

  4. 我应该用形状像路径或DrawingVisual类来实现实际的再presentation。路径是直线前进,但我担心有数百CurvePoints的性能。

  5. 我应该使用变换旋转切线还是蛮好做一些数学三角在文件后面的code?

  6. 是否大致结构的意义,还是你提出一个完全不同的方法?


解决方案

  1. 您似乎就在眼前, WPF偷跑是正确的工具优秀的,但我猜你有一个了。


  2. 请用户控件个人在这些案件之一:


    • 您使用的是相同的XAML所有的地方(干)

    • 您XAML文件变得太大(得到一些组件从)

    • 您的需求的从某些类
    • 继承

  3. 这取决于你想多少codebehind。结果
    你可以,你在你的评论所说,使用一个ItemsControl为只要您需要多个项目之间进行选择的容器。所以这可能也对曲线的水平来完成,而不是仅仅在点的曲线上的水平。根据您希望如何处理实际的线条和曲线绘制,你甚至可以对​​那些一个ItemsControl。 (在一个侧面说明:你不会有虚拟化开箱不过,因为您的项目将不会有一个固定的高度)


  4. 路径是与数百CurvePoints的确定。如果你有10.000,我会说你可以得到的问题。

  5. 无法想象如何变换应该用在这里,也许装饰器里面。

  6. 您的结构看起来不错。你将能够实现这一切。我会建议,虽然我会怎样做:

首先使用MVVM。


  • CurveEditor结果
    列表框(面板=帆布)(的ItemsSource =曲线)(ItemTemplate中= CurveControl)


  • CurveControl


    • 画布(背景=透明)LT =我不知道,如果标准白色的,但你不希望其他重叠曲线...

      • CurveName

      • 列表框(面板=画布(背景=透明))(的ItemsSource = CurveParts)

      • ListBox(Panel=Canvas(Background=Transparent))(ItemsSource=CurvePoints)(ItemTemplate=>EditPointControl)



  • EditPointControl


    • 画布

      • 拇指(模板=椭圆)(名称= CenterHandle)(有一些Visualstates的选择和切线隐藏)

      • 拇指(模板=椭圆)(名称= LeftHandle)

      • 拇指(模板=椭圆)(名称= RightHandle)

      • 线(绑定X / Y为中心点和LeftHandlePoint)

      • 线(绑定X / Y为中心点和RightHandlePoint)



我已经指出来的ItemTemplate设置为ListBox。但是,您可以风格,但是你想在列表框中(我认为标准样式,包括边框,你可能想要删除或设置bordersize = 0),并设置代替ItemTemplate中的<一个href=\"http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemcontainerstyle.aspx\"相对=nofollow> ItemContainerStyle 并绑定到IsSelected让您从您的视图模型(看的这里明白我的意思)。

因此​​,视图模型是这样的:

   -  CurveEditorViewModel
     - - 的ObservableCollection LT; CurveViewModel&GT;曲线
- CurveViewModel
     - 字符串标签
     - (点将labelPlacement)
     - 布尔IsSelected
     - - 的ObservableCollection LT; CurvePointViewModel&GT; CurvePoints
     - - 的ObservableCollection LT; CurvePartViewModel&GT; CurveParts
- CurvePointViewModel
     - 点位置
     - 布尔IsSelected
     - 点LeftHandle
     - 点RightHandle - CurvePartViewModel
     - CurvePointViewModel StartPoint可以
     - CurvePointViewModel端点
     - 路径CurvePath

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

我可能改进它,因为我去但那会是我的第一个猜测。

有可能要注意一些细节。例如:对拇指的风格可能是在中间,可见圆形一种无形的大点的周围背景=透明。这样你可以有你的圈子可见小,但有用户使用tumb在周围地区的小圆圈。

修改

这里是大拇指的例子:

 &LT;拇指宽度=8HEIGHT =8光标=手保证金= -  4&GT;
            &LT; Thumb.Template&GT;
                &LT;的ControlTemplate的TargetType =拇指&GT;
                    &LT;网格和GT;
                        &LT;椭圆填充=透明保证金= - 6/&GT;
                        &LT;椭圆行程=红StrokeThickness =2/&GT;
                    &LT; /网格和GT;
                &LT; /控件模板&GT;
            &LT; /Thumb.Template>
        &LT; /拇指&GT;

只要你想在一个特定的点画布边距设置为负的宽度和高度的一半将放置在该点的圆心上的定位这一点。此外,具有透明填充和保证金内心的椭圆-6,你会得到解决内部(小)圆6个像素更大的半径在这里你可以拖动滑块。

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

  • freely scalable and moveable axis
  • different interpolation types per curve point (Linear, Cubic, Spline)
  • Tangents (joined and broken)
  • Selecting one or several points to edit (move, scale, delete) via Fence or Click
  • Only show handles and highlights for selected curve points

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.

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 - 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
            • RightTangent - UserControl for the right tangent handle
              • RightTangentThumb - For modifying the handle
          • CurvePointCenter - Visualisation of the actual point, select state and interpolation type.
            • 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. Can you recommend any tutorials or books that might help me (I already got Illustrated WPF, WPF Control Development Unleashed, and a couple of other)
  2. Should minor elements like the Tangents be individual UserControls?
  3. What container is best suited for hosting the individual "Curves", "EditPoints" and "Tangents". Right now, I use Canvas and Canvas.SetLeft/SetTop to position the children, but that feels "strange".
  4. Should I use "Shapes" like Path or DrawingVisual-Classes to implement actual representation. Path is straight forward, but I am concerned about performance with hundreds of CurvePoints.
  5. Should I use Transforms to rotate the tangents or is just fine to do some triangulation math in the code behind files?
  6. Does the structure roughly make sense, or do you suggest a completely different approach?

解决方案

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

  2. make individual UserControls in one of these cases:

    • 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
  3. 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)

  4. Path is OK with hundreds of CurvePoints. If you have 10.000, I'd say you could get problems.
  5. can't imagine how a transform should be used here, maybe inside an Adorner.
  6. your structure looks good. you will be able to implement all of this. I will suggest though how I would do it:

first of all use MVVM.

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

  • CurveControl

    • Canvas(Background=Transparent) <= I'm not sure if standard is white, but you don't want to overlap other Curves...
      • CurveName
      • ListBox(Panel=Canvas(Background=Transparent))(ItemsSource=CurveParts)
      • ListBox(Panel=Canvas(Background=Transparent))(ItemsSource=CurvePoints)(ItemTemplate=>EditPointControl)
  • EditPointControl

    • Canvas
      • Thumb(Template = Ellipse) (Name=CenterHandle) (with some Visualstates for Selection and hiding of Tangents)
      • Thumb(Template = Ellipse) (Name=LeftHandle)
      • Thumb(Template = Ellipse) (Name=RightHandle)
      • Line (Binding X/Y to Centerpoint and LeftHandlePoint)
      • Line (Binding X/Y to Centerpoint and RightHandlePoint)

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

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.

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.

EDIT:

here is an Example for the Thumb:

        <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>

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天全站免登陆