DiagramDesigner的学习心得一
2013-01-06 15:10
99 查看
DiagramDesigner是CodeProject上关于WPF的控件模板,移动拖放,改变控件大小,旋转的很好的文章。
在博客园博主周金根的博客上也有相应的介绍。它总共分四部分,每部分都循序渐进。
首先我们来讲第一部分,关于控件的移动,和改变大小,MoveAndResize.
MoveResize项目运行起来的效果如下:
在MoveResize项目的window1.xaml中:
这两个ContentControl控件一个是左边的菱形,另一个则是一个圆形。样式都采用了DesignerItemTemplate.
对上面的两段xaml里的TemplateBinding和ContentPresenter我们可以引用周金根博主里面的解释:
限制目标类型
ControlTemplate和Style一样,也有一个TargetType属性来限制模板可以被应用到的类型上,如果没有一个显示的TargetType,则目标类型将被隐式的设置为Control。由于没有默认的控件模板,所以它与Style是不同的,当使用TargetType时不允许移除模板的x:Key。
模板绑定TemplateBinding
在控件模板中,从目标元素插入属性值的关键是数据绑定,我们可以通过一个简单、轻量级的模板绑定TemplateBinding来处理。TemplateBinding的数据源总是目标元素,而Path则是目标元素的任何一个依赖属性。使用方式如上例的{TemplateBinding ContentControl.Content},如果我们设置了TargetType,可以更简单的使用为{TemplateBinding Content}
TemplateBinding仅仅是一个便捷的设置模板绑定的机制,对于有些可冻结的属性(如Brush的Color属性)时绑定会失败,这时候我们可以使用常规的Binding来达到同样效果,通过使用一个RelativeSource,其值为{Relative Source TemplatedParent}以及一个Path。
ContentPresenter
在控件模板中应该使用轻量级的内容显示元素ContentPresenter,而不是ContentControl。ContentPresenter显示的内容和ContentControl是一样的,但是ContentControl是一个带有控件模板的成熟控件,其内部包含了ContentPresenter。
如果我们在使用ContentPresenter时忘记了将它的Content设置为{TemplateBinding Content}时,它将隐式的假设{TemplateBinding Content}就是我们需要的内容
与触发器交互
在模板内部可以使用触发器,但是在进行绑定时需要注意只能使用Binding,因为触发器位于控件可视树模板外部
我们看到在DesignerItemTemplate里还有两个MoveThumbTemplate 和 ResizeDecoratorTemplate .
MoveThumbTemplate其实就是一个Rectangle搞定。我们把它的Fill改成Blue看下:
ResizeDecoratorTemplate就是四个角上的
我们来看看ResizeThumb这个类是怎么实现的:
MoveThumbTemplate是基于MoveThumb类的:
下篇我们来分析下旋转 还有 根据Adorner来怎么实现。
在博客园博主周金根的博客上也有相应的介绍。它总共分四部分,每部分都循序渐进。
首先我们来讲第一部分,关于控件的移动,和改变大小,MoveAndResize.
MoveResize项目运行起来的效果如下:
在MoveResize项目的window1.xaml中:
<ContentControl Width="130" MinWidth="50" Height="130" MinHeight="50" Canvas.Top="150" Canvas.Left="470" Template="{StaticResource DesignerItemTemplate}"> <Ellipse Fill="Red" IsHitTestVisible="False"/> </ContentControl> <ContentControl Width="130" MinWidth="50" Height="130" MinHeight="50" Canvas.Top="150" Canvas.Left="150" Template="{StaticResource DesignerItemTemplate}"> <Path Fill="Blue" Data="M 0,5 5,0 10,5 5,10 Z" Stretch="Fill" IsHitTestVisible="False"/> </ContentControl>
这两个ContentControl控件一个是左边的菱形,另一个则是一个圆形。样式都采用了DesignerItemTemplate.
<!-- Designer Item Template--> <ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl"> <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"> <s:MoveThumb Template="{StaticResource MoveThumbTemplate}" Cursor="SizeAll"/> <Control Template="{StaticResource ResizeDecoratorTemplate}"/> <ContentPresenter Content="{TemplateBinding ContentControl.Content}"/> </Grid> </ControlTemplate>
对上面的两段xaml里的TemplateBinding和ContentPresenter我们可以引用周金根博主里面的解释:
限制目标类型
ControlTemplate和Style一样,也有一个TargetType属性来限制模板可以被应用到的类型上,如果没有一个显示的TargetType,则目标类型将被隐式的设置为Control。由于没有默认的控件模板,所以它与Style是不同的,当使用TargetType时不允许移除模板的x:Key。
模板绑定TemplateBinding
在控件模板中,从目标元素插入属性值的关键是数据绑定,我们可以通过一个简单、轻量级的模板绑定TemplateBinding来处理。TemplateBinding的数据源总是目标元素,而Path则是目标元素的任何一个依赖属性。使用方式如上例的{TemplateBinding ContentControl.Content},如果我们设置了TargetType,可以更简单的使用为{TemplateBinding Content}
TemplateBinding仅仅是一个便捷的设置模板绑定的机制,对于有些可冻结的属性(如Brush的Color属性)时绑定会失败,这时候我们可以使用常规的Binding来达到同样效果,通过使用一个RelativeSource,其值为{Relative Source TemplatedParent}以及一个Path。
ContentPresenter
在控件模板中应该使用轻量级的内容显示元素ContentPresenter,而不是ContentControl。ContentPresenter显示的内容和ContentControl是一样的,但是ContentControl是一个带有控件模板的成熟控件,其内部包含了ContentPresenter。
如果我们在使用ContentPresenter时忘记了将它的Content设置为{TemplateBinding Content}时,它将隐式的假设{TemplateBinding Content}就是我们需要的内容
与触发器交互
在模板内部可以使用触发器,但是在进行绑定时需要注意只能使用Binding,因为触发器位于控件可视树模板外部
我们看到在DesignerItemTemplate里还有两个MoveThumbTemplate 和 ResizeDecoratorTemplate .
MoveThumbTemplate其实就是一个Rectangle搞定。我们把它的Fill改成Blue看下:
ResizeDecoratorTemplate就是四个角上的
我们来看看ResizeThumb这个类是怎么实现的:
public class ResizeThumb : Thumb { public ResizeThumb() { //当有逻辑焦点或鼠标捕获时,随着鼠标位置改变一次或多次 DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta); } private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e) { Control designerItem = this.DataContext as Control;//获取父控件,通过DataContext if (designerItem != null) { double deltaVertical, deltaHorizontal; switch (VerticalAlignment) { case VerticalAlignment.Bottom: deltaVertical = Math.Min(-e.VerticalChange, designerItem.ActualHeight - designerItem.MinHeight);//计算减小的高度 designerItem.Height -= deltaVertical;//减小高度 break; case VerticalAlignment.Top: deltaVertical = Math.Min(e.VerticalChange, designerItem.ActualHeight - designerItem.MinHeight); Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + deltaVertical);//重新设置相对于相对于Canvas的上边距 designerItem.Height -= deltaVertical; break; default: break; } switch (HorizontalAlignment) { case HorizontalAlignment.Left: deltaHorizontal = Math.Min(e.HorizontalChange, designerItem.ActualWidth - designerItem.MinWidth); Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + deltaHorizontal);//重新设置相对于Canvas的左边距 designerItem.Width -= deltaHorizontal;//减小宽度 break; case HorizontalAlignment.Right: deltaHorizontal = Math.Min(-e.HorizontalChange, designerItem.ActualWidth - designerItem.MinWidth); designerItem.Width -= deltaHorizontal; break; default: break; } } e.Handled = true; } }
MoveThumbTemplate是基于MoveThumb类的:
public class MoveThumb : Thumb { public MoveThumb() { DragDelta += new DragDeltaEventHandler(this.MoveThumb_DragDelta); } private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e) { Control designerItem = this.DataContext as Control;//获取父控件,通过DataContext if (designerItem != null) { double left = Canvas.GetLeft(designerItem);//获取现在相对于Canvas画布的左边距 double top = Canvas.GetTop(designerItem);//获取现在相对于Canvas画布的上边距 Canvas.SetLeft(designerItem, left + e.HorizontalChange);//e.HorizontalChange 水平改变大小,有可能为负 Canvas.SetTop(designerItem, top + e.VerticalChange);//e.VerticalChange 垂直改变大小,有可能为负 } } }
下篇我们来分析下旋转 还有 根据Adorner来怎么实现。
相关文章推荐
- NUMA与英特尔下一代Xeon处理器学习心得(1) 推荐
- Effective C++学习心得
- 学习心得之通信篇(TCP/IP协议栈)
- LINQ学习心得分享--------(五)LINQ TO SQL实用详解
- httpclient的一些学习心得
- msdatagrid学习心得
- 看到一篇好的文章计算机专业的学习心得
- Echarts的使用和学习心得体会
- 分布式计算开源框架Hadoop学习心得之1
- 南大软院大神养成计划——第一天学习心得
- 心得丨学习人工智能AI需要哪些最基础的知识?
- BT源代码学习心得(三):种子文件的编码方式
- 国庆假期学习html的一些心得
- 我的MYSQL学习心得(1) 简单语法
- js 学习心得2
- Web学习的一点心得
- eclipse debug 学习心得
- sublime学习心得
- <Introduction to Discrete-event systems>学习心得
- AJAX学习心得分享----(一)AJAX初识+原生态AJAX