zoukankan      html  css  js  c++  java
  • 走进WPF系列学习之二 如何用WPF绘制与配置2D图形界面

    今天在公司比较闲所以就连续学了两节WPF,下面是要跟大家探讨一下关于如何用WPF绘制与配置2D图像界面,说来好笑,刚刚公司的同事遇到一个有关WPF的问题——怎样在WPF的设计页面化一个红色箭头。刚刚看到这个问题,我思考了一下,也动手做了一下,不过能力有限还是自己没有解决,于是开始Google,Baidu。在网上有很多解决方案,但是用的方法都是差不多的:写一个画箭头的class,然后在需要用到箭头的地方实例化箭头Class,并给相应的坐标赋值,最后将对象Add到Canvas控件中。

    用WPF画箭头

    自定义的画箭头Class代码:

    View Code
    namespace ZhangWei.WPF.Shapes
    {
    using System;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Shapes;


    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public sealed class Arrow : Shape
    {
    #region Dependency Properties

    public static readonly DependencyProperty X1Property = DependencyProperty.Register("X1", typeof(double), typeof(Arrow), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
    public static readonly DependencyProperty Y1Property = DependencyProperty.Register("Y1", typeof(double), typeof(Arrow), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
    public static readonly DependencyProperty X2Property = DependencyProperty.Register("X2", typeof(double), typeof(Arrow), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
    public static readonly DependencyProperty Y2Property = DependencyProperty.Register("Y2", typeof(double), typeof(Arrow), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
    public static readonly DependencyProperty HeadWidthProperty = DependencyProperty.Register("HeadWidth", typeof(double), typeof(Arrow), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
    public static readonly DependencyProperty HeadHeightProperty = DependencyProperty.Register("HeadHeight", typeof(double), typeof(Arrow), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));

    #endregion

    #region CLR Properties

    [TypeConverter(typeof(LengthConverter))]
    public double X1
    {
    get { return (double)base.GetValue(X1Property); }
    set { base.SetValue(X1Property, value); }
    }

    [TypeConverter(typeof(LengthConverter))]
    public double Y1
    {
    get { return (double)base.GetValue(Y1Property); }
    set { base.SetValue(Y1Property, value); }
    }

    [TypeConverter(typeof(LengthConverter))]
    public double X2
    {
    get { return (double)base.GetValue(X2Property); }
    set { base.SetValue(X2Property, value); }
    }

    [TypeConverter(typeof(LengthConverter))]
    public double Y2
    {
    get { return (double)base.GetValue(Y2Property); }
    set { base.SetValue(Y2Property, value); }
    }

    [TypeConverter(typeof(LengthConverter))]
    public double HeadWidth
    {
    get { return (double)base.GetValue(HeadWidthProperty); }
    set { base.SetValue(HeadWidthProperty, value); }
    }

    [TypeConverter(typeof(LengthConverter))]
    public double HeadHeight
    {
    get { return (double)base.GetValue(HeadHeightProperty); }
    set { base.SetValue(HeadHeightProperty, value); }
    }

    #endregion

    #region Overrides

    protected override Geometry DefiningGeometry
    {
    get
    {
    // Create a StreamGeometry for describing the shape
    StreamGeometry geometry = new StreamGeometry();
    geometry.FillRule = FillRule.EvenOdd;

    using (StreamGeometryContext context = geometry.Open())
    {
    InternalDrawArrowGeometry(context);
    }

    // Freeze the geometry for performance benefits
    geometry.Freeze();

    return geometry;
    }
    }

    #endregion

    #region Privates

    private void InternalDrawArrowGeometry(StreamGeometryContext context)
    {
    double theta = Math.Atan2(Y1 - Y2, X1 - X2);
    double sint = Math.Sin(theta);
    double cost = Math.Cos(theta);

    Point pt1 = new Point(X1, this.Y1);
    Point pt2 = new Point(X2, this.Y2);

    Point pt3 = new Point(
    X2 + (HeadWidth * cost - HeadHeight * sint),
    Y2 + (HeadWidth * sint + HeadHeight * cost));

    Point pt4 = new Point(
    X2 + (HeadWidth * cost + HeadHeight * sint),
    Y2 - (HeadHeight * cost - HeadWidth * sint));

    context.BeginFigure(pt1, true, false);
    context.LineTo(pt2, true, true);
    context.LineTo(pt3, true, true);
    context.LineTo(pt2, true, true);
    context.LineTo(pt4, true, true);
    }

    #endregion


    }
    }

    给一个调用的例子:

    首先在页面中放一个Canvas控件用来在其中显示箭头,

    <Window x:Class="Tomers.WPF.Shapes.MainWindow"
    xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
    ="MainWindow" Height="350" Width="525">
    <Grid>
    <Canvas Height="104" Margin="42,45,313,0" Name="canvas1" VerticalAlignment="Top" >
    </Canvas>
    </Grid>
    </Window>

    下面就可以在后台代码中让箭头出现在Canvas中,代码:

    using System.Windows;
    using System.Windows.Media;

    namespace Tomers.WPF.Shapes
    {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
    public MainWindow()
    {
    InitializeComponent();
    Arrow arrow = new Arrow();
    arrow.X1 = 2;
    arrow.Y1 = 10;
    arrow.X2 = 60;
    arrow.Y2 = 10;
    arrow.HeadWidth = 10;
    arrow.HeadHeight = 2;
    arrow.Stroke = Brushes.Red;
    arrow.StrokeThickness = 2;
    canvas1.Children.Add(arrow);
    }
    }
    }

    在代码中

    arrow.X1 = 2;
    arrow.Y1 = 10;
    arrow.X2 = 60;
    arrow.Y2 = 10;

    用来指定箭头在画布Canvas中的位置,其中X1,Y1表示箭头的开始坐标,X2,Y2表示箭头的结束坐标。当配置完成之后将对象Add到Canvase的子节点中。

    源代码下载

    当我很兴奋的告诉同事问题已经被我拿下来啦,但是当她看到那个箭头Class时,直接否定了我。原因代码太多了接受不了。说要用XAML代码来完成,不用C#。于是让我寻求第二种解决方法的动力就来了。正在我焦头乱额时,突然让我看到了曙光,那就是——WPF绘制与配置2D图像界面。

    其实也不是什么高深的东东,主要用到了Line和Path,这两个东西简直太神奇了,我先前不知道第二种方法的原因是:我以为只能用ToolBox里面提供的控件,但是在Toolbox里面都没有可以画直线是东东。让我找到了Line顾名思义是用来画直线的,Path可以用来画曲线,有了这两个东西,画箭头俺还不是小菜吗。呵呵。。。。。。

    只需要短短的几行XAML就搞定了上面大量代码搞定的事咯: 

    <Window x:Class="Tomers.WPF.Shapes.MainWindow"
    xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
    ="MainWindow" Height="350" Width="525">
    <Grid>
    <Canvas Height="152" Name="canvas2" Width="200" Canvas.Left="43" Canvas.Top="90">
    <Line X1="30" Y1="100" X2="100" Y2="100" Stroke="Red" StrokeThickness="3" Width="226" Height="140" />
    <Path Stroke="Red" StrokeThickness="3" Data="M85,105 100,100 85,95" />
    </Canvas>
    </Grid>
    </Window>

    一句C#代码都不要太爽啦。

    下面就更深一步的来研究一下其他的用来画图的东东,来看看下面这个图吧:

    很简单,这些都是小Case,你们可以自由发挥,用最简单最基本的东西可以画出很多好看的图形。实现上面图像的XAML代码是:

    <Window x:Class="Demo2.MainWindow"
    xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
    ="MainWindow" Height="350" Width="525">
    <Grid Name="grid1">
    <Line X1="100" Y1="150" X2="200" Y2="200" Stroke="Red" StrokeThickness="2"/>
    <Ellipse Height="237" HorizontalAlignment="Left" Margin="299,12,0,0" Name="ellipse1" Stroke="Black" VerticalAlignment="Top" Width="143" Fill="Yellow" StrokeThickness="6" />
    <Button Content="Button" Height="77" HorizontalAlignment="Left" Margin="42,222,0,0" Name="button1" VerticalAlignment="Top" Width="203" Click="button1_Click" />
    <Button Content="Button" Height="60" HorizontalAlignment="Left" Margin="278,239,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" />
    <Canvas Height="139" HorizontalAlignment="Left" Margin="10,10,0,0" Name="canvas1" VerticalAlignment="Top" Width="252" >
    <Ellipse Canvas.Left="10" Canvas.Top="10" Height="25" Name="ellipse2" Stroke="Black" Width="50" />
    <Path Stroke="Blue" StrokeThickness="2" Data="M2,2 Q30,40 4,50"/>
    <Polygon Stroke="Red" StrokeThickness="4" Points="40,100 80,120 60,160">
    <Polygon.Fill>
    <SolidColorBrush Color="Yellow"/>
    </Polygon.Fill>
    </Polygon>
    </Canvas>
    </Grid>
    </Window>

    很少吧。这里很有趣,大家可以自由发挥,我实在没什么美术天分,所以画不出来好东西,在这里也不给大家画啦。

    我把源码分享给大家吧(源码下载

  • 相关阅读:
    vue 组件创建与销毁
    防止vue组件渲染不更新
    es6 includes(), startsWith(), endsWith()
    相对路径 绝对路径
    控制台打印输出
    vue2.0 $router和$route的区别
    Vue 响应式数据说明
    Linux下多线程下载工具myget
    LNMP环境简单教程
    linux下不同服务器间数据传输(wget,scp)
  • 原文地址:https://www.cnblogs.com/zwzw/p/good.html
Copyright © 2011-2022 走看看