您的位置:首页 > 其它

DiagramDesigner的学习心得一

2013-01-06 15:10 99 查看
DiagramDesignerCodeProject上关于WPF的控件模板,移动拖放,改变控件大小,旋转的很好的文章。

在博客园博主周金根的博客上也有相应的介绍。它总共分四部分,每部分都循序渐进。

首先我们来讲第一部分,关于控件的移动,和改变大小,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来怎么实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: