C# wpf利用附加属性实现界面上定义装饰器

 更新时间:2022年12月16日 16:32:05   作者:CodeOfCC  
装饰器是wpf中可以浮在控件上面的一种组件,我们通常可以用来实现一些诸如控件拖动点、提示框、自定义鼠标等界面功能。本文主要是利用附加属性实现界面上定义装饰器,需要的可以参考下

前言

装饰器是wpf中可以浮在控件上面的一种组件,我们通常可以用来实现一些诸如控件拖动点、提示框、自定义鼠标等界面功能。装饰器的用法其实还是比较复杂的,几乎需要完全再cs中编写所有代码,对于样式要求较高的情况下,完全在cs中些控件的样式是比较困难的。为了改变这种状况,我们可以使用附加属性将装饰器的逻辑封装,提供一个可以在界面上定义的属性。

一、如何实现

1、实现装饰器

由于Adorner是一个抽象类不能直接实现,所有我们需要定义一个子类实现并它。

class NormalAdorner : Adorner
{
    /// <summary>
    /// 构造方法
    /// </summary>
    /// <param name="adornedElement">被添加装饰器的元素</param>
    /// <param name="child">放到装饰器中的元素</param>
    public NormalAdorner(UIElement adornedElement, UIElement child) : base(adornedElement);
    protected override Visual GetVisualChild(int index);
    protected override int VisualChildrenCount;
    protected override Size ArrangeOverride(Size finalSize);
}

2、定义附加属性

通过propa快捷定义一个名称为AdornerContent的附加属性其类型UIElement。

public static UIElementGetAdornerContent(DependencyObject obj)
{
    return (UIElement)obj.GetValue(AdornerContent);
}
public static void SetAdornerContent(DependencyObject obj, Control value)
{
    obj.SetValue(AdornerContent, value);
}
// Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty AdornerContent =
    DependencyProperty.RegisterAttached("AdornerContent", typeof(UIElement), typeof(AdornerHelper), new PropertyMetadata(null));

3、加入装饰层

在附加属性改变事件中,进行装饰层的添加。

public void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var c = d as UIElement;
    //获取装饰层
    var layer = AdornerLayer.GetAdornerLayer(c);
    //添加装饰器
     layer.Add(new NormalAdorner(c, (UIElement)e.NewValue));
}

二、完整代码

AdornerHelper.cs

using System;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
namespace AC
{
    internal class AdornerHelper
    {
        public static UIElement GetAdornerContent(DependencyObject obj)
        {
            return (UIElement)obj.GetValue(AdornerContent);
        }
        public static void SetAdornerContent(DependencyObject obj, UIElement value)
        {
            obj.SetValue(AdornerContent, value);
        }
        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AdornerContent =
            DependencyProperty.RegisterAttached("AdornerContent", typeof(UIElement), typeof(AdornerHelper), new PropertyMetadata(null, (d, e) =>
            {
                var c = d as FrameworkElement;
                if (c == null)
                    return;
                var adronerContent = e.NewValue as UIElement;
                if (!c.IsLoaded)
                {
                    if (adronerContent != null)
                    {
                        RoutedEventHandler l = null;
                        l = (s, E) =>
                        {
                            var content = GetAdornerContent(c);
                            if (content != null)
                            {
                                var layer = AdornerLayer.GetAdornerLayer(c);
                                if (layer == null)
                                    throw new Exception("获取控件装饰层失败,控件可能没有装饰层!");
                                layer.Add(new NormalAdorner((UIElement)c, (UIElement)e.NewValue));
                            }
                            c.Loaded -= l;
                        };
                        c.Loaded += l;
                    }
                }
                else
                {
                    var layer = AdornerLayer.GetAdornerLayer(d as Visual);
                    if (layer == null)
                        throw new Exception("获取控件装饰层失败,控件可能没有装饰层!");
                    if (e.OldValue != null)
                    {

                        var adorners = layer.GetAdorners(c);
                        foreach (var i in adorners)
                        {
                            if (i is NormalAdorner)
                            {
                                var na = i as NormalAdorner;
                                if (na.Child == e.OldValue)
                                {
                                    layer.Remove(i);
                                    break;
                                }
                            }
                        }
                    }
                    if (adronerContent != null)
                    {
                        layer.Add(new NormalAdorner((UIElement)c, (UIElement)e.NewValue));
                    }
                }
            }));

        class NormalAdorner : Adorner
        {
            UIElement _child;
            /// <summary>
            /// 构造方法
            /// </summary>
            /// <param name="adornedElement">被添加装饰器的元素</param>
            /// <param name="child">放到装饰器中的元素</param>
            public NormalAdorner(UIElement adornedElement, UIElement child) : base(adornedElement)
            {
                _child = child;
                AddVisualChild(child);
            }
            public UIElement Child { get { return _child; } }
            protected override Visual GetVisualChild(int index)
            {
                return _child;
            }
            protected override int VisualChildrenCount
            {
                get
                {
                    return 1;
                }
            }
            protected override Size ArrangeOverride(Size finalSize)
            {
                _child.Arrange(new Rect(new Point(0, 0), finalSize));
                return finalSize;
            }
        }
    }
}

三、使用示例

<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp2"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        >
    <Grid>
        <Border Background="RoyalBlue" Width="320" Height="180" CornerRadius="10">
             <!--添加装饰器-->
            <ac:AdornerHelper.AdornerContent>
                <Grid >
                    <Grid.Resources>
                        <Style TargetType="Thumb">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="Thumb">
                                        <Border BorderBrush="Gray" BorderThickness="2" CornerRadius="8"  Background="White"></Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </Grid.Resources>
                    <!--左-->
                    <Thumb  Margin="-8,0,0,0" Width="16" Height="16" HorizontalAlignment="Left" VerticalAlignment="Center" Cursor="SizeWE"/>
                    <!--上-->
                    <Thumb  Margin="0,-8,0,0" Width="16" Height="16" HorizontalAlignment="Center" VerticalAlignment="Top" Cursor="SizeNS"/>
                    <!--右-->
                    <Thumb  Margin="0,0,-8,0" Width="16" Height="16" HorizontalAlignment="Right" VerticalAlignment="Center" Cursor="SizeWE"/>
                    <!--下-->
                    <Thumb  Margin="0,0,0,-8" Width="16" Height="16" HorizontalAlignment="Center" VerticalAlignment="Bottom" Cursor="SizeNS"/>
                    <!--左上-->
                    <Thumb  Margin="-8,-8,0,0" Width="16" Height="16" HorizontalAlignment="Left" VerticalAlignment="Top" Cursor="SizeNWSE"/>
                    <!--右上-->
                    <Thumb  Margin="0,-8,-8,0" Width="16" Height="16" HorizontalAlignment="Right" VerticalAlignment="Top"  Cursor="SizeNESW"/>
                    <!--右下-->
                    <Thumb  Margin="0,0,-8,-8" Width="16" Height="16" HorizontalAlignment="Right" VerticalAlignment="Bottom"  Cursor="SizeNWSE"/>
                    <!--左下-->
                    <Thumb  Margin="-8,0,0,-8" Width="16" Height="16" HorizontalAlignment="Left" VerticalAlignment="Bottom" Cursor="SizeNESW"/>
                </Grid>
            </ac:AdornerHelper.AdornerContent>
        </Border>
    </Grid>
</Window>

效果预览

总结

以上就是今天要讲的内容,在界面上定义装饰器主要目的是为了方编写复杂样式,使用方式有了较大的变化。想要灵活使用则需要对wpf有一定的深入了解。但从另外一个角度来说在界面上定义装饰器和使用Grid布局调整层叠达到相同效果,可能本质上区别不太大,至少在控件树上两者是一模一样的。总的来说个人觉得这是一种比较有意思的装饰器使用方法。

到此这篇关于C# wpf利用附加属性实现界面上定义装饰器的文章就介绍到这了,更多相关C# wpf界面定义装饰器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之

相关文章

  • C#实现航班预订系统

    C#实现航班预订系统

    这篇文章主要为大家详细介绍了C#实现航班预订系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 使用C#实现自己封装的Modbus工具类库

    使用C#实现自己封装的Modbus工具类库

    Modbus通讯协议在工控行业的应用是很多的,并且也是上位机开发的基本技能之一,所以本文主要为大家介绍了如何使用C#封装一个Modbus工具类库,需要的可以参考下
    2024-02-02
  • 使用C#来编写一个异步的Socket服务器

    使用C#来编写一个异步的Socket服务器

    这篇文章主要介绍了使用C#来编写一个异步的Socket服务器,通过无阻塞机制来获取更高的处理效率,需要的朋友可以参考下
    2015-07-07
  • Unity接入百度AI实现货币识别

    Unity接入百度AI实现货币识别

    本文主要介绍了在Unity中接入百度AI,从而实现货币识别,可以返回货币的名称、代码、面值、年份信息等,感兴趣的可以跟随小编学习一下
    2022-01-01
  • C# 使用 OleDbConnection 连接读取Excel的方法

    C# 使用 OleDbConnection 连接读取Excel的方法

    这篇文章主要介绍了C# 使用 OleDbConnection 连接读取Excel的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • 详细介绍C#之文件校验工具的开发及问题

    详细介绍C#之文件校验工具的开发及问题

    目前校验文件使用最多的是MD值和SHA值,不外乎有些使用CRC,前段时间微软发布了VisualStudio正式版,win镜像,微软官方给出的校验方式都是校验文件的SHA值。下面详细介绍C#之文件校验工具的开发及问题,需要的朋友可以参考下
    2015-07-07
  • C#中Abstract 、Virtual和Override的使用及区别

    C#中Abstract 、Virtual和Override的使用及区别

    C#中virtual,abstract,override用于方法重载,子类覆盖了父类的相同方法,父类中的实现不可能再被外面调用。本文给大家重点介绍C#中Abstract 、Virtual和Override的使用及区别,需要的朋友参考下吧
    2021-06-06
  • C#遍历集合与移除元素的方法

    C#遍历集合与移除元素的方法

    这篇文章主要介绍了C#遍历集合与移除元素的方法,结合实例形式分析了C#使用for循环遍历集合以及add与Remove方法进行元素添加与移除的使用技巧,需要的朋友可以参考下
    2016-06-06
  • C# 动态输出Dos命令执行结果的实例(附源码)

    C# 动态输出Dos命令执行结果的实例(附源码)

    这篇文章主要介绍了C# 动态输出Dos命令执行结果的实例,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • C#基于XNA生成随机颜色的方法

    C#基于XNA生成随机颜色的方法

    这篇文章主要介绍了C#基于XNA生成随机颜色的方法,涉及XNA Color类的使用技巧,需要的朋友可以参考下
    2015-06-06

最新评论