[Aaronyang] 写给自己的WPF4.5 笔记19[Visual类图文并茂讲解]

文章虽小,内容还好,且看且珍惜。

当界面上使用数千个矢量图形,例如实时统计图,粒子碰撞,比如超级玛丽游戏,图像一直在绘,过量的使用WPF的元素系统和Shape类会使用程序变慢,所以我们需要使用Visual类手动进行渲染。

Visual类是很多WPF元素的父类。所以掌握它当然很重要了。

Visual的开销小于Geometry小于Path



Visual作为抽象类,有UIElement这个子类,也有Viewport3DVisual类(3D知识中的)

放置Visual的对象的容器:ContainerVisual类,继承该类的子类有DrawingVisual类。

DrawingVisual.RenderOpen()会返回个可用于定义可视化内容的DrawingContext对象。

DrawingContext类使用完要Close,类似文件流读写完要close,所以你可以使用using关键字了,使用完自动释放对象。

有了DrawingContext后就可以很轻松的开始绘制你想要的图形了。

除了基本的DrawLine,DrawRectangle,DrawRoundedRectangle,DrawEllipse,当然还有上一篇博客说到的DrawGeometry,还有DrawDrawing来放置Geometry,Drawing对象。

同样的类似winform的验证码绘制代码,DrawText,DrawImage(例如做水印),DrawVedio。

还有些方法可能第一次接触,例如Pop()撤销上一次Push操作,PushClip(),PushEffect(),PushOpacity(),PushOpacityMask(),PushTransform()等

例如代码:

      private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            DrawingVisual dv=new DrawingVisual();
            using (DrawingContext dc=dv.RenderOpen())
            {
                Pen pen = new Pen(new SolidColorBrush(Colors.Red), 2);
                //Pen pen = new Pen(Brushes.DarkRed, 2);
                dc.DrawEllipse(Brushes.DarkRed, null, new Point(20, 20), 20, 20);
                dc.DrawLine(pen, new Point(10, 20), new Point(100, 200));
                dc.DrawLine(pen, new Point(0, 10), new Point(80, 150));
            }
        }

DrawingVisual对象一旦关闭,可视化对象不可修改。

以上代码都还算简单,接着我们需要自定义一个Visual放置的面板用于显示元素。除了2个父类的操作,我们还添加了新增和删除,还有一个获取

 public class DrawingCanvas : Panel {

        protected override Visual GetVisualChild(int index)
        {
            return base.GetVisualChild(index);
        }
        protected override int VisualChildrenCount
        {
            get
            {
                return base.VisualChildrenCount;
            }
        }

        public void AddVisual(Visual visual) { 

        }
        public void DeleteVisual(Visual visual)
        {

        }

        public DrawingVisual GetVisual(Point point) {
            return null;
        }

    }

我们规定了约定,接下来新增具体代码

  public class DrawingCanvas : Panel
    {
        private List<Visual> visuals = new List<Visual>();

        protected override Visual GetVisualChild(int index)
        {
            return visuals[index];
        }
        protected override int VisualChildrenCount
        {
            get
            {
                return visuals.Count;
            }
        }

        public void AddVisual(Visual visual)
        {
            visuals.Add(visual);

            base.AddVisualChild(visual);
            base.AddLogicalChild(visual);
        }
        public void DeleteVisual(Visual visual)
        {
            visuals.Remove(visual);

            base.RemoveVisualChild(visual);
            base.RemoveLogicalChild(visual);
        }

        public DrawingVisual GetVisual(Point point)
        {
            return null;
        }

    }

为了让用户单击面板,我们可以拿到单击时候的点下面的visual,我们使用"命中测试"的wpf技术去做

    public DrawingVisual GetVisual(Point point)
        {
            HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
            return hitResult.VisualHit as DrawingVisual;
        }

能够单击的都是可视化的,我们也在AddVisual中将visual对象加入了可视化树。

由于单击的地方,或者一块区域,可能有多个Visual,所以我们在返回一个List<DrawingVisual>

到目前为止,这些代码都还是挺好理解的。这里很好的使用了 矩形命中测试和点命中测试

  private List<DrawingVisual> hits = new List<DrawingVisual>();
        public List<DrawingVisual> GetVisuals(Geometry region)
        {
            hits.Clear();
            GeometryHitTestParameters parameters = new GeometryHitTestParameters(region);
            HitTestResultCallback callback = new HitTestResultCallback(this.HitTestCallback);
            VisualTreeHelper.HitTest(this, null, callback, parameters);
            return hits;
        }

        private HitTestResultBehavior HitTestCallback(HitTestResult result)
        {
            GeometryHitTestResult geometryResult = (GeometryHitTestResult)result;
            DrawingVisual visual = result.VisualHit as DrawingVisual;
            if (visual != null &&
                geometryResult.IntersectionDetail == IntersectionDetail.FullyInside)
            {
                hits.Add(visual);
            }
            return HitTestResultBehavior.Continue;
        }

接下来新建一个窗体

<Window x:Class="ay3dDemo.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ay3dDemo"
        Title="Window1" Height="600" Width="800" Loaded="Window_Loaded">
    <Grid x:Name="lay">
        <Grid.RowDefinitions>
            <RowDefinition Height="51*"/>
            <RowDefinition Height="518*"/>
        </Grid.RowDefinitions>
        <local:DrawingCanvas Grid.Row="1" x:Name="dcanvas" Background="White" ClipToBounds="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

        </local:DrawingCanvas>
    </Grid>
</Window>

接下来后台增加drawingvisual到这个面板上

   private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            DrawingVisual dv = new DrawingVisual();
            using (DrawingContext dc = dv.RenderOpen())
            {
                Pen pen = new Pen(new SolidColorBrush(Colors.Red), 2);
                //Pen pen = new Pen(Brushes.DarkRed, 2);
                dc.DrawEllipse(Brushes.DarkRed, null, new Point(20, 20), 20, 20);
                dc.DrawLine(pen, new Point(10, 20), new Point(100, 200));
                dc.DrawLine(pen, new Point(0, 10), new Point(80, 150));
            }
            dcanvas.AddVisual(dv);
        }

效果图:

为什么显示呢,因为我们加入到了可视化树上面。

接下来我们增加面板的左键单击事件

    <Grid x:Name="lay">
        <Grid.RowDefinitions>
            <RowDefinition Height="51*"/>
            <RowDefinition Height="518*"/>
        </Grid.RowDefinitions>
        <local:DrawingCanvas Grid.Row="1" x:Name="dcanvas" Background="White" ClipToBounds="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                            MouseLeftButtonDown="dcanvas_MouseLeftButtonDown"
                             >

        </local:DrawingCanvas>
        <RadioButton Content="圆形" HorizontalAlignment="Left" Margin="77,10,0,0" VerticalAlignment="Top" Name="rdoEllipse"/>
        <RadioButton Content="正方形" HorizontalAlignment="Left" Margin="158,10,0,0" VerticalAlignment="Top" Name="rdosquare"/>
        <RadioButton Content="删除" HorizontalAlignment="Left" Margin="269,10,0,0" VerticalAlignment="Top" Name="rdodelete"/>
        <RadioButton Content="移动" HorizontalAlignment="Left" Margin="393,10,0,0" VerticalAlignment="Top" Name="rdomove"/>
    </Grid>

接下来,后台左键事件中,使用点命中测试

 private void dcanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Point pointClicked = e.GetPosition(dcanvas);
            if (rdodelete.IsChecked.Value)
            {
                DrawingVisual dv = dcanvas.GetVisual(pointClicked);
                if (dv != null)
                {
                    dcanvas.DeleteVisual(dv);
                }
            }
        }

接下来我们再次绘制矩形和圆形

   private void dcanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Point pointClicked = e.GetPosition(dcanvas);
            if (rdodelete.IsChecked.Value)
            {
                DrawingVisual dv = dcanvas.GetVisual(pointClicked);
                if (dv != null)
                {
                    dcanvas.DeleteVisual(dv);
                }
            }
            else if (rdoEllipse.IsChecked.Value)
            {
                DrawingVisual dv = new DrawingVisual();
                using (DrawingContext dc = dv.RenderOpen())
                {
                    Pen pen = new Pen(new SolidColorBrush(Colors.Red), 2);
                    dc.DrawEllipse(Brushes.DarkRed, pen, pointClicked, 20, 20);
                    dcanvas.AddVisual(dv);
                }
            }
            else if (rdosquare.IsChecked.Value)
            {
                DrawingVisual dv = new DrawingVisual();
                using (DrawingContext dc = dv.RenderOpen())
                {
                    Pen pen = new Pen(new SolidColorBrush(Colors.Red), 5);
                    dc.DrawRectangle(Brushes.YellowGreen, pen, new Rect(pointClicked, new Size(50, 30)));
                    dcanvas.AddVisual(dv);
                }
            }
        }

代码简单易懂,不讲了,知识让你对Visual有认识,不会太害怕这个知识点了。

所以到目前位置你都可以自定义Geometry了,如果你想保存最后的工程图,你可以记住位置和图形就ok了。

关于移动也就不写了,因为可以拿到Visual对象就行了,想怎么操作就怎么操作了。

Pen是边框,Brush是填充画刷

接下来讲一下矩形区域命中测试,首先我们就需要创建一个矩形

思路:

鼠标左键按下,标记状态是多选状态,公用一个pen,brush,drawingvisual,共享起始点的位置。

1.左键按下,创建一个DrawingVisual,并放入面板,标记起始点,设置当前鼠标移动时候的状态,捕获鼠标 dcanvas.CaptureMouse();

  public bool isMultiSelecting = false;
        private DrawingVisual selectionSquare;
        private Brush selectionSquareBrush = Brushes.Transparent;
        private Pen selectionSquarePen = new Pen(Brushes.Black, 1);
        private Point selectionSquareTopLeft;
        private void dcanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Point pointClicked = e.GetPosition(dcanvas);
            if (rdoMouseMul.IsChecked.Value)
            {
                selectionSquare = new DrawingVisual();
                dcanvas.AddVisual(selectionSquare);
                selectionSquareTopLeft = pointClicked;
                isMultiSelecting = true;
                dcanvas.CaptureMouse();
            }            .....         }

2.鼠标移动时候,如果是多选时候就触发代码,设置pen的风格是虚线,并开始绘制,这里我们可以得到起点和中点,所以可以创建一个虚线的矩形 Visual。

  private void dcanvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (isMultiSelecting)
            {
                Point pointDragged = e.GetPosition(dcanvas);
                selectionSquarePen.DashStyle = DashStyles.Dash;

                using (DrawingContext dc = selectionSquare.RenderOpen())
                {
                    dc.DrawRectangle(selectionSquareBrush, selectionSquarePen,
                        new Rect(selectionSquareTopLeft, pointDragged));
                }
            }
        }

鼠标抬起时候,我们根据起点和终点创建一个RectangleGeometry,用于做区域命中测试

  private void dcanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {

            if (isMultiSelecting)
            {
                RectangleGeometry geometry = new RectangleGeometry(
                    new Rect(selectionSquareTopLeft, e.GetPosition(dcanvas)));
                List<DrawingVisual> visualsInRegion = dcanvas.GetVisuals(geometry);
                lblmsg.Content = String.Format("你选中了{0}个visual", visualsInRegion.Count);
                isMultiSelecting = false;
                dcanvas.DeleteVisual(selectionSquare);
                dcanvas.ReleaseMouseCapture();
            }
        }

虚线矩形在鼠标抬起时候,从面板中移除,我们并且释放鼠标捕获。

效果图演示

更高性能的WriteableBitmap对象,这里我也不太会,所以不讲了。

讲了这么多基础图形的东西,感觉本篇文章实用的一些东西还挺少,其实了解了Visual可以做出很多高级效果。这里后面我们再讲。



为了让文章充实,我暴露一个我的AyImage4Button按钮的制作方法

图片的区域使用,我找了一张4种按钮状态的图片,我们使用按钮去操作

下面看下我的代码

  <Style x:Key="{x:Type control:AyImage4Button}"  TargetType="{x:Type control:AyImage4Button}">
        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Background" Value="Red"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true" >
                        <Border.Background>
                            <ImageBrush ImageSource="{Binding Path=Icon, RelativeSource={RelativeSource TemplatedParent}}" Stretch="Uniform" Viewbox="0,0 0.25,1"/>
                        </Border.Background>
                        <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsDefaulted" Value="true">
                            <Setter Property="Background" TargetName="border">
                                <Setter.Value>
                                    <ImageBrush ImageSource="{Binding Path=Icon, RelativeSource={RelativeSource TemplatedParent}}" Stretch="Uniform" Viewbox="0,0 0.25,1"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Background" TargetName="border">
                                <Setter.Value>
                                    <ImageBrush ImageSource="{Binding Path=Icon, RelativeSource={RelativeSource TemplatedParent}}" Stretch="Uniform" Viewbox="0.25,0 0.25,1"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter Property="Background" TargetName="border">
                                <Setter.Value>
                                    <ImageBrush ImageSource="{Binding Path=Icon, RelativeSource={RelativeSource TemplatedParent}}" Stretch="Uniform" Viewbox="0.5,0 0.25,1"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Background" TargetName="border">
                                <Setter.Value>
                                    <ImageBrush ImageSource="{Binding Path=Icon, RelativeSource={RelativeSource TemplatedParent}}" Stretch="Uniform" Viewbox="0.75,0 0.25,1"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using System.ComponentModel;
using System.Windows;

namespace Ay.Framework.WPF.Controls
{
    public class AyImage4Button:Button
    {
        /// <summary>
        /// Image4Button
        /// </summary>
        public ImageSource Icon
        {
            get { return (ImageSource)GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Icon.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IconProperty =
            DependencyProperty.Register("Icon", typeof(ImageSource), typeof(AyImage4Button), new PropertyMetadata(null));

    }

}

这里我使用了ImageBrush的Viewbox截取图片的区域部分

ok,我们来使用下

首先引入:

         xmlns:local2="clr-namespace:Ay.Framework.WPF.Controls"

上方引入样式后

   <local2:AyImage4Button x:Name="CloseBtn" Width="32" Height="24" Margin="605,8,0,17"
                                HorizontalAlignment="Left" VerticalAlignment="Center" Icon="close.png"
                            />

ImageBrush还有TileMode就是平铺方式,除了百分比的区域截图,还有绝对尺寸的区域截图ViewportUnits

还有个VisualBrush,做复制样子的。比如应用,做倒影,指定Visual的属性就可以了,倒影,然后你再旋转图形,然后设置OpacityMask

  <local2:AyImage4Button x:Name="CloseBtn" Width="32" Height="24" Margin="605,8,0,17"
                                HorizontalAlignment="Left" VerticalAlignment="Center" Icon="close.png"
                            />
        <Rectangle Margin="605,48,155,5" Width="32" Height="24">
            <Rectangle.Fill>
                <VisualBrush Visual="{Binding ElementName=CloseBtn}"/>
            </Rectangle.Fill>
        </Rectangle>

还有个画刷叫BitmapCacheBrush,用法类似VisualBrush,设置Rectangle的Fill的Brush为BitmapCacheBrush,然后使用Target替代Visual,然后指定BitmapCache为,例如BitmapCache使用位图缓存,当然第一次缓存就会有一些延迟了。这里暂时不讲了。比如一个小球在运动,背景是死的,球在背景上动,那么如果背景不是缓存的,那么背景将会一直刷新,就会很费内存,此时的画刷就可以使用BitmapCacheBrush了,它的好处不言而喻了。

接下来,我需要讲一下RenderTransform和LayoutTransform的区别。

LayoutTransform是在转换操作之前就计算好布局了。而RenderTransform是在呈现时候,例如,两个旋转的按钮

 <StackPanel  Margin="25"  Background="LightYellow">
      <Button Padding="5" HorizontalAlignment="Left">
        <Button.RenderTransform>
          <RotateTransform Angle="35" CenterX="45" CenterY="5" />
        </Button.RenderTransform>
        <Button.Content>I‘m rotated 35 degrees</Button.Content>
      </Button>
      <Button Padding="5" HorizontalAlignment="Left">I‘m not</Button>
    </StackPanel>

    <StackPanel  Margin="25"  Background="LightYellow">
      <Button Padding="5" HorizontalAlignment="Left">
        <Button.LayoutTransform>
          <RotateTransform Angle="35" CenterX="45" CenterY="5" />
        </Button.LayoutTransform>
        <Button.Content>I‘m rotated 35 degrees</Button.Content>
      </Button>
      <Button Padding="5" HorizontalAlignment="Left">I‘m not</Button>
    </StackPanel>

可以看出区别了吧。有时候如果变化的时候发现不对,你就换一下转换布局的方式     o(∩_∩)o 哈哈

关于动画一章,我为什么还不讲,原因是,Blend中基本的太容易做了,建议大家还是试试,前台代码转后台代码的写法试试。练习,因为我的一些想要的动画都是先用blend写好动画草稿,然后自己在后台转换为后台代码去是实现的,例如那个环状图AyArcChart。

好了,从下篇开始,我就要一直讲3d的知识了,当然也会有很炫的3d的窗口动画。

       =============潇洒的版权线==========www.ayjs.net===== Aaronyang ========= AY =========== 安徽 六安 杨洋 ==========   未经允许不许转载 =========

       -------------------小小的推荐,作者的肯定,读者的支持。推不推荐不重要,重要的是希望大家能把WPF推广出去,别让这么好的技术消失了,求求了,让我们为WPF技术做一份贡献。-----------------

时间: 2024-08-09 14:42:19

[Aaronyang] 写给自己的WPF4.5 笔记19[Visual类图文并茂讲解]的相关文章

[Aaronyang] 写给自己的WPF4.5 笔记18[几何图形*Geometry图文并茂讲解]

为什么要掌握?因为WPF 3D知识很多与它Geometry对比,所以我要系统学一下. --学会用Geometry给Path的Data属性填充. 图形可以转换成路径,Path的值,当然你也可以直接使用Rectangle控件 路径当然有路径的好处了,我在Blend5公开课3中演示了很多路径的用法,例如运动路径,布局路径,剪切路径等 当然在Blend中可以快速变成路径 转换后的代码如下: <Path Data="M2.5,2.5 L47.5,2.5 L47.5,97.5 L2.5,97.5 z&

[Aaronyang] 写给自己的WPF4.5 笔记11[自定义控件-AyImageButton篇 1/4]

我的文章一定要对读者负责-否则不是好文章  ----       www.ayjs.net  aaronyang技术分享 文章导航: 介绍vs2013 WPF开发,属性代码相关技巧 实战AyImageButton 1.0细用慢讲,学会用户控件,依赖属性,属性回调事件 诞生AyImageButton 1.1 支持 控件简单写法,支持自定义AyImageButton写法,提供详细的API 效果图: AyImageButton记录 源码下载:http://pan.baidu.com/s/1eQlHly

[Aaronyang] 写给自己的WPF4.5 笔记13[二维自定义控件技巧-可视化状态实战,自定义容器,注册类命令,用户控件补充]

 我的文章一定要做到对读者负责,否则就是失败的文章  ---------   www.ayjs.net    aaronyang技术分享 博文摘要:欢迎大家来支持我的<2013-2015 Aaronyang的又一总结,牧童遥指纳尼村>绝对好文章 关于<写给自己的WPF4.5 笔记14,已在官网发布> 1.讲解了自定义控件加入命令支持的两种手段,补充用户控件的客户定义模板 2.实战的方式讲解了无外观控件,可以让使用者定义模板,讲解模板PART,使用可视化状态组,动画的使用 效果演示:

[Aaronyang] 写给自己的WPF4.5 笔记[2依赖属性]

人生的意义不在于拿一手好牌,而在于打好一手坏牌 --Aaronyang的博客(www.ayjs.net)-www.8mi.me =============时隔两年后再看WPF========== 因为以前的经验,所以继承FrameworkElement,我就简写继承FWE ,继承UIElement就写继承UIE 后面重头戏就是blend中的开发,不想写的千篇一律.如果期待,左侧有关注按钮. 个人感觉,下面的这张图标比较重要,它或许有些帮助.我看东西只看分析出原理,你就可以拓三返一. Tip: 只

[Aaronyang] 写给自己的WPF4.5 笔记8[复杂数据处理三步曲,数据视图精讲1/3]

真的好累了 ,笑了.做回自己吧       -------------      Aaronyang技术分享 www.ayjs.net 博文摘要: 详细介绍了WPF中视图的种类和开始学之前的准备工作 视图的 分页视图导航 DEMO1 详细讲解了 视图中xaml的声明方式,以及xaml的排序和分组 DEMO2 实例讲解了DataTable的BindingListCollectionView的类似操作 DEMO3 讲解了LINQ中的过滤 Predicate委托,以及过滤的几种方式 讲解了 视图中后台

[Aaronyang] 写给自己的WPF4.5 笔记6[三巴掌-大数据加载与WPF4.5 验证体系详解 2/3]

我要做回自己--Aaronyang的博客(www.ayjs.net) 博客摘要: Virtualizing虚拟化DEMO 和 大数据加载的思路及相关知识 WPF数据提供者的使用ObjectDataProvider 和 XmlDataProvider WPF验证 第一:使用自带的属性SET抛出异常,前台捕捉到异常,描红 第二:我们可以自定义验证规则,替代刚开始的异常捕捉验证 第三:我们可以使用INotifyDataErrorInfo方式,增加异常,并实现了验证通知和还原非法值 第四:我们使用了Er

[Aaronyang] 写给自己的WPF4.5 笔记[3MenuItem中的icon]

敢于尝试,就等于你已经向成功迈出了第一步 --Aaronyang的博客(www.ayjs.net)-www.8mi.me =============时隔两年后再看WPF========== 因为以前的经验,所以继承FrameworkElement,我就简写继承FWE ,继承UIElement就写继承UIE 后面重头戏就是blend中的开发,不想写的千篇一律.如果期待,左侧有关注按钮. 1. v1.0菜单 新建WPF项目,右键项目-属性-资源          导入几个项目用到的图标 第一种:带图

[Aaronyang] 写给自己的WPF4.5 笔记15[AyArc诞生-WPF版本绚丽的环状图,Ay制作,AyWindow强势预览]

 我的文章一定要做到对读者负责,否则就是失败的文章  ---------   www.ayjs.net    aaronyang技术分享 Ay.Framework.WPF-AyWindow强势预览,点击前往 1. AyArcChart效果图:DEMO下载 2. 使用用法: 新建一个WPF项目AyArcChartDemo,并拷贝AyArcChart用户控件xaml,由于我使用的是Arc控件,所以我们还需要引入Expression的部分dll 2.1 绝佳第一次使用 讲解几个ayarc重要的属性 A

[Aaronyang] 写给自己的WPF4.5 笔记10[层次数据需求处理,TreeView绿色文章1/4]

 我的文章一定要做到对读者负责,否则就是失败的文章  ---------   www.ayjs.net    aaronyang技术分享 AY留言: 文章根据难易,我根据游戏的规则进行了分色,希望读者能选择自己的能力去读.白色<绿色<蓝色<紫色<橙色<红色 博文摘要: 简单的TreeView静态写法,了解展开事件,选中事件 关于磁盘驱动器的图标的获得,文件夹的图标的获得,文件的图标的获得,系统自己shell32.dll的图标的获得(例如我的电脑,回收站等icon) 关于Tre