WPF整理-为控件添加自定义附加属性

原文:WPF整理-为控件添加自定义附加属性

附加属性,大家都不陌生,最常见的是Canvas.Left/Canvas.Top,类似的也有Grid.Row/Grid.Column等附加属性。举个最常见的例子

<Canvas>
   <Ellipse Fill="Red" Width="100" Height="60" Canvas.Left="56" Canvas.Top="98"/>
</Canvas>

需要说明的是并不是所有的附加属性都是元素放进去后才会有附加效果,上面的例子只是刚好是这种错觉的巧合情况,Grid.Row也属于这种巧合。
还是举个反例来说明

<Canvas>
   <Button Content="Copy" ToolTip="Copy the Selected Items"ToolTipService.ShowOnDisabled="True"/>
</Canvas>

ToolTipService类是一个静态类,和Button风马牛不相及,两者之间没有任何关系。

这就是关于附加属性DebugLZQ认为需要说明的地方。

为控件添加一个自定义的附加属性

1.我们有这样的一个XAML

    <Canvas>
        <Ellipse Fill="Red" Width="100" Height="60" />
        <Rectangle Fill="Blue" Width="80" Height="80" Canvas.Left="100" Canvas.Top="100" />
        <Button Content="Hello" Canvas.Left="130" Canvas.Top="30" FontSize="20" />
    </Canvas>

假如,我们需要实现控件绕中心旋转一定的角度。通常我们需要写类似的Rotate

        <Ellipse Fill="Red" Width="100" Height="60" RenderTransformOrigin=".5,.5">
            <Ellipse.RenderTransform>
                <RotateTransform Angle="30" />
            </Ellipse.RenderTransform>
        </Ellipse>

当然这样OK,程序运行没有问题。
但,缺点是需要写较多的代码;当我们需要为页面其他所有元素实现旋转时,又需要写大量类似的代码。

我们可以通过附加属性来简化代码。如何做呢?

2.为工程添加一个名为RotationManager的类,我们在这个类中添加一个附加属性,让其他都能使用这个附加属性。

我们在类中键入"propa"

和依赖属性类似,连按2次Tab,修改相应命名,如下:

        public static double GetAngle(DependencyObject obj)
        {
            return (double)obj.GetValue(AngleProperty);
        }

        public static void SetAngle(DependencyObject obj, double value)
        {
            obj.SetValue(AngleProperty, value);
        } 

        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(RotationManager), new PropertyMetadata(0.0));

这样我们就完成了附加属性的定义。
为了能够在XAML中使用,在XAML中添加如下映射。

<Window x:Class="CreatingAnAttachedProperty.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:local="clr-namespace:CreatingAnAttachedProperty"

这样,页面上的元素就可以使用这个附加属性了,如下:

    <Canvas>
        <Ellipse Fill="Red" Width="100" Height="60" Canvas.Left="56" Canvas.Top="98" local:RotationManager.Angle="30"/>
        <Rectangle Fill="Blue" Width="80" Height="80" Canvas.Left="285" Canvas.Top="171" local:RotationManager.Angle="45" />
        <Button Content="Hello" Canvas.Left="265" Canvas.Top="48" FontSize="20" local:RotationManager.Angle="60"/>
    </Canvas>

3.此时编辑器,没有任何旋转,若我们此时运行程序,也没有任何的旋转效果,为什么?因为我们只是添加了一个附加属性,给它付了个初值,当值改变的时候,我们并没有添加相应的处理逻辑。
依次,我们需要返回RotationManager.cs添加相应的值改变事件及事件处理逻辑。如下:

        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(RotationManager), new PropertyMetadata(0.0,OnAngleChanged));

        private static void OnAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var element = obj as UIElement;
            if (element != null)
            {
                element.RenderTransformOrigin = new Point(0.5, 0.5);
                element.RenderTransform = new RotateTransform((double)e.NewValue);
            }
        }

添加完成后,我们在编辑器中,看到如下效果:

如果我们运行,则效果如下:

相比于前面挨个挨个的添加Rotate效果,程序是Clearn很多?这就是附加属性带来的便利。

完整的RotationManager.cs如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;//necessary

namespace CreatingAnAttachedProperty
{
    class RotationManager:DependencyObject
    {
        public static double GetAngle(DependencyObject obj)
        {
            return (double)obj.GetValue(AngleProperty);
        }

        public static void SetAngle(DependencyObject obj, double value)
        {
            obj.SetValue(AngleProperty, value);
        } 

        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(RotationManager), new PropertyMetadata(0.0,OnAngleChanged));

        private static void OnAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var element = obj as UIElement;
            if (element != null)
            {
                element.RenderTransformOrigin = new Point(0.5, 0.5);
                element.RenderTransform = new RotateTransform((double)e.NewValue);
            }
        }
    }
}

Update:

WPF: Creating parameterized styles with attached properties

原文地址:https://www.cnblogs.com/lonelyxmas/p/9479068.html

时间: 2024-11-08 21:14:30

WPF整理-为控件添加自定义附加属性的相关文章

WPF中查找控件的扩展类

在wpf中查找控件要用到VisualTreeHelper类,但这个类并没有按照名字查找控件的方法,于是搜索网络,整理出下面这个类,感觉用起来很是方便. 贴出来,供大家参考. /// <summary> /// WPF/Silverlight 查找控件扩展方法 /// </summary> public static class VisualHelperTreeExtension { /// <summary> /// 根据控件名称,查找父控件 /// elementNa

WPF多线程访问控件

大家知道WPF中多线程访问UI控件时会提示UI线程的数据不能直接被其他线程访问或者修改,该怎样来做呢? 分下面两种情况 1.WinForm程序 1 2 1)第一种方法,使用委托: 3 private delegate void SetTextCallback(string text); 4 private void SetText(string text) 5 { 6 // InvokeRequired需要比较调用线程ID和创建线程ID 7 // 如果它们不相同则返回true 8 if (thi

WPF中Ribbon控件的使用

这篇博客将分享如何在WPF程序中使用Ribbon控件.Ribbon可以很大的提高软件的便捷性. 上面截图使Outlook 2010的界面,在Home标签页中,将所属的Menu都平铺的布局,非常容易的可以找到想要的Menu.在Outlook 2003时代,将Home下面的Menu都垂直的排列下来,操作的便捷程度降低了很多.Ribbon的布局会随着窗体的变化动态的调整. 上面的图片中标注了Ribbon的4个区块. 下面我们就在WPF中使用Ribbon控件来实现一个简单的界面. 1. 添加System

Wpf使用Winform控件后Wpf元素被Winform控件遮盖问题的解决

有人会说不建议Wpf中使用Winform控件,有人会说建议使用Winform控件在Wpf下的替代方案,然而在实际工作中由于项目的特殊需求,考虑到时间.成本等因素,往往难免会碰到在WPF中使用Winfrom控件的问题,我们知道Wpf可以通过使用WindowsFormsHost容器调用Winform控件,但是在一些场合需要将Wpf元素显示在Winform控件的上层,此时就会出现Wpf元素被Winform控件遮盖的问题. 一.场景再现 接到公司命令,在时间紧迫的情况下,需要将原来的Winform程序(

Xceed WPF 主题皮肤控件Xceed Professional Themes for WPF详细介绍

Xceed Professional Themes for WPF是一款为你的整个应用程序提供完美WPF主题风格的控件,包含Office 2007和Windows 7,可以应用到任何微软官方的WPF控件. 具体功能: WPF/.NET技术: 完全基于WPF创建,由C#和XAML编写,适用于.NET 3.5和4.0 完整的XAML源代码可用 兼容CLS 完全整合帮助文档到Visual Studio里 主要功能: 提供了7种预定义WPF主题风格 Glass 主题风格 Media 主题风格,使您的应用

WPF送走控件的focus方法

我们可以调用Focus()方法,让WPF控件获得焦点, 那我现在不想要焦点了, 如何把这个包袱抛出去? 可以,  恩, 没有Unfocus(), 但下面的方法也许可行(把焦点抛给另一个不知道的控件): myControl.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); WPF送走控件的focus方法,布布扣,bubuko.com

在WPF的WebBrowser控件中屏蔽脚本错误的提示

在WPF中使用WebBrowser控件显示网页时,经常会报脚本错误的提示,如何屏蔽掉这些错误提示呢.方法是定义如下方法: public void SuppressScriptErrors(WebBrowser wb, bool Hide) { FieldInfo fiComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);

InteropBitmap指定内存,绑定WPF的Imag控件时刷新问题。

1.InteropBitmap指定内存,绑定WPF的Imag控件的Source属性 创建InteropBitmap的时候,像素的格式必须为PixelFormats.Bgr32, 如果不是的话在绑定到Image控件的Source属性,刷新新界面(BitmapSource.Invalidate())的时候会造成内存泄露. 2. 内存映射: //内存共享类 internal class Win32Mess { [DllImport("VCamBridge.dll", EntryPoint =

在WPF程序中将控件所呈现的内容保存成图像(转载)

在WPF程序中将控件所呈现的内容保存成图像 转自:http://www.cnblogs.com/TianFang/archive/2012/10/07/2714140.html 有的时候,我们需要将控件所呈现的内容保存成图像保存下来,例如:InkCanvas的手写墨迹,WebBrowser中的网页等.可能有人会说,这个不就是截图嘛,找到控件的坐标和大小,调用截图API不就可以了嘛.的确,对于规则的控件来说,通过截图的却可以实现,可是,如果控件不规则或不透明度不是100%,则会把其背景控件的视觉效