首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >用XAML/WPF实现复杂曲线编辑器的策略

用XAML/WPF实现复杂曲线编辑器的策略
EN

Stack Overflow用户
提问于 2011-03-11 18:12:07
回答 1查看 3.1K关注 0票数 7

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

  • 可自由伸缩和可移动的轴
  • 每个曲线点的不同插值类型(线性、三次、样条)
  • 切线(连接和断裂)
  • 选择一个或几个点,通过栅栏或单击编辑(移动、缩放、删除)
  • 仅显示选定曲线点的句柄和突出显示

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

我已经积累了一些实现自定义UserControls和模板的经验。但我要确保,我不会错过任何明显的解决方案。我计划有一个通用的XAML树:

  • CurveEditor -保存所有内容的窗口
    • MainThumb:启用拖动和缩放编辑器范围
    • XAxis:在左侧绘制一些比例尺的UserControl
    • YAxis:在底部绘制一些比例尺的UserControl
    • 曲线:容纳曲线的画布
      • 曲线:单曲线的UserControl
        • CurveName -曲线标号
        • CurveLine - DrawingVisual,它将通过采样样条函数的内部实现来呈现实际曲线。
        • CurveEditPoints -画布,保存所有编辑点
          • 用于单个编辑点的CurveEditPoint - UserControl
          • 左切线手柄的LeftTangent - UserControl
          • LeftTangentThumb -用于修改句柄

代码语言:javascript
代码运行次数:0
运行
复制
            - **RightTangent** - UserControl for the right tangent handle  
            - **RightTangentThumb** - For modifying the handle

代码语言:javascript
代码运行次数:0
运行
复制
            - **CurvePointCenter** - Visualisation of the actual point, select state and interpolation type.  
            - **CurvePointThumb** - Thumb to select and drag point around

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

  1. 你能推荐一些可能对我有帮助的教程或书籍吗(我已经得到了插图WPF、WPF控件开发以及其他几本)。
  2. 像切线这样的次要元素应该是单独的UserControls吗?
  3. 什么样的容器最适合承载个人“曲线”、"EditPoints“和”切线“。现在,我用画布和Canvas.etLeft/SetTop来定位孩子们,但这感觉很“奇怪”。
  4. 我是否应该使用“形状”(如Path或DrawingVisual类)来实现实际表示。Path是直截了当的,但我关心的是数百个CurvePoints的性能。
  5. 我是应该使用转换来旋转切线,还是只是在文件后面的代码中做一些三角剖分的数学?
  6. 这种结构是否大致合理,或者你是否建议了一种完全不同的方法?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-03-14 13:33:03

  1. 您似乎手头有正确的工具,WPF释放是优秀的,但我想您已经有了这个工具。
  2. 在其中一种情况下制作单独的UserControls:
代码语言:javascript
代码运行次数:0
运行
复制
- 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

  1. 这取决于你想要多少代码。 正如您在注释中建议的那样,您可以使用ItemsControl作为容器,用于需要在多个项之间进行选择的任何地方。因此,这也可以在曲线的水平上进行,而不仅仅是在曲线上的点的水平上。根据您想要处理的实际线条和曲线的绘制方式,您甚至可以为这些绘制一个ItemsControl。(顺便提一句:您将不会有虚拟化,虽然,因为您的项目将不会有一个恒定的高度)
  2. 路径可以使用数百个CurvePoints。如果你有10.000,我会说你会有麻烦的。
  3. 无法想象如何在这里使用转换,也许在Adorner内部。
  4. 你的结构看起来不错。您将能够实现所有这些。不过,我会建议我如何去做:

首先使用MVVM。

  • CurveEditor ListBox(Panel=Canvas)(ItemsSource=Curves)(ItemTemplate=CurveControl)
  • CurveControl
代码语言:javascript
代码运行次数:0
运行
复制
- 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
代码语言:javascript
代码运行次数:0
运行
复制
- 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)

我已经声明将ItemTemplate设置为ListBox。不过,您可以随意设置列表框的样式(我认为标准样式包括一个边框,您可能希望删除该边框或设置bordersize=0),并将其设置为ItemTemplate ( ItemContainerStyle ),并绑定到IsSelected,这样您就可以从ViewModel中控制IsSelected (我的意思是查看这里 )。

视图模型如下所示:

代码语言:javascript
代码运行次数:0
运行
复制
- 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并重新计算您要公开的路径。

我可能会改进我的做法,但这将是我的第一猜测。

有些细节你可能需要留心。拇指的样式可能是中间的一个可见的圆圈,和background=transparent周围的一个看不见的更大的圆圈。这样,你就可以让你的可见圈小,但让用户使用在一个区域周围的小圆圈。

编辑

下面是拇指的一个例子:

代码语言:javascript
代码运行次数:0
运行
复制
        <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更大的半径围绕在中心(较小的)圆圈,你可以拖动拇指。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5276701

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档