• DiagramDesigner的学习心得一


    DiagramDesignerCodeProject上关于WPF的控件模板,移动拖放,改变控件大小,旋转的很好的文章。

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

    首先我们来讲第一部分,关于控件的移动,和改变大小,MoveAndResize.

    MoveResize项目运行起来的效果如下:

    image

    在MoveResize项目的window1.xaml中:

    image

      <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里还有两个MoveThumbTemplateResizeDecoratorTemplate .

    MoveThumbTemplate其实就是一个Rectangle搞定。我们把它的Fill改成Blue看下:

    image

    ResizeDecoratorTemplate就是四个角上的image

    我们来看看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来怎么实现。

  • 相关阅读:
    51nod 1051【基础】
    HDU5971【瞎搞】
    Lightoj1018 【状压DP】
    HDU2604【矩阵快速幂】
    HDU1501【简单DP】
    HDU3555【数位DP】
    Lightoj1037【状压DP】
    51nod 1099【贪心】
    HDU5950【矩阵快速幂】
    51nod 1049【经典】
  • 原文地址:https://www.cnblogs.com/johnwonder/p/2847736.html
Copyright © 2020-2023  润新知