代码改变世界

漫游WPF基类

2010-12-08 16:59  Clingingboy  阅读(1752)  评论(0编辑  收藏  举报

 

DependencyObject

这个类要有多重要就有多重要,是WPF依赖属性的基础(依赖属性又与其他特性息息相关),在设计WPF类时,如果该对象并不会当做一个元素呈现,且你想拥有绑定等功能,那么继承该类将带来极大的灵活性.

public class TestDP:DependencyObject
{

    public int Number
    {
        get { return (int)GetValue(NumberProperty); }
        set { SetValue(NumberProperty, value); }
    }

    public static readonly DependencyProperty NumberProperty =
        DependencyProperty.Register("Number", typeof(int), typeof(TestDP), 
        new UIPropertyMetadata(0));

}

通过GetValue和SetValue方法使用DP属性,如果你不想继承该类,那么还有一个选择,那就是附加属性,可能你的很多类已经设计好了,已经有了基类.

public class TestAttachDP 
{

    public static int GetNumber(DependencyObject obj)
    {
        return (int)obj.GetValue(NumberProperty);
    }

    public static void SetTimeLineSynchronousHost(DependencyObject obj, int value)
    {
        obj.SetValue(NumberProperty, value);
    }

    public static readonly DependencyProperty NumberProperty =
        DependencyProperty.RegisterAttached("Number", typeof(int), typeof(TestAttachDP),
        new UIPropertyMetadata(0));

}

依赖属性是构建灵活的WPF系统的基础

System.Windows.Media.Visual

该类构建了一个视觉树的概念,并提供了一些与绘图有关的属性,但与其本身WPF绘图引擎无关,其只提供属性.

有那么一种元素其本身并不会绘制任何图形,但其却还是存在视觉树中.它的存在可以用作数据存储或者当做与布局无关的容器使用.

实际中继承此类的意义不大,因为其不具备绘图功能.其意义在于打下扎实的基类基础

public class NoRenderVisual:Visual
{
    protected override int VisualChildrenCount
    {
        get
        {
            return base.VisualChildrenCount;
        }
    }

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

添加这样的视觉树意义不大,我们也无需继承重写,因为内置有更好的选择

image

System.Windows.Media.ContainerVisual

一个继承自Visual的类,使得其有一个基本的容器(Children)结构,该类充当视觉树容器更加适合,否则你只能选择Visual来重写了,实际上该类你可能并不常用,由于其自身并没有布局系统,即使添加了元素也无法呈现,作为辅助使用

public class OwnContainerVisual:ContainerVisual
{
    public OwnContainerVisual()
    {
        var element = new Button(){Width = 100,Height = 20,Content = "hello"};
        this.Children.Add(element);
        
    }
}
现在不再使用AddVisualChild方法添加Visual,而是使用Children集合

System.Windows.Media.DrawingVisual

DrawingVisual是真正一个轻量级并派的上用场的类,因为其拥有RenerOpen方法,获取DrawingContext,这样就开始画图了

public class RectanlgeVisual : DrawingVisual
{
    public RectanlgeVisual()
    {
        using (var dc=this.RenderOpen())
        {
            dc.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 100));
        } 
    }
}

何谓轻量级即,只有最基础的绘图功能,但没有相关的事件,布局,模板等特性,但是效率会更好.复杂度会更高.使用方面不是特别的方便.

System.Windows.UIElement.UIElement

如果说DrawingVisual是轻量级,那么UIElement就是重量级的了,到了这一步元素拥有的基础的事件和布局系统,可以用过重写OnRender方法重绘控件的外观

public class RectangleUIElement:UIElement
{
    public RectangleUIElement()
    {
        Brush = Brushes.Red;
    }

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);
        Brush = Brushes.Green;
        //re-render
        this.InvalidateVisual();
    }

    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        base.OnMouseUp(e);
        Brush = Brushes.Red;
        //re-render
        this.InvalidateVisual();
    }

    public Brush Brush { get; set; }

    protected override void OnRender(DrawingContext drawingContext)
    {
        drawingContext.DrawRectangle(Brush, null, new Rect(0, 0, 100, 100));
        base.OnRender(drawingContext);
    }
}

image

就此打住,接下来的目标还是研究其布局系统