C#?wpf利用附加屬性實(shí)現(xiàn)界面上定義裝飾器
前言
裝飾器是wpf中可以浮在控件上面的一種組件,我們通??梢杂脕?lái)實(shí)現(xiàn)一些諸如控件拖動(dòng)點(diǎn)、提示框、自定義鼠標(biāo)等界面功能。裝飾器的用法其實(shí)還是比較復(fù)雜的,幾乎需要完全再cs中編寫(xiě)所有代碼,對(duì)于樣式要求較高的情況下,完全在cs中些控件的樣式是比較困難的。為了改變這種狀況,我們可以使用附加屬性將裝飾器的邏輯封裝,提供一個(gè)可以在界面上定義的屬性。
一、如何實(shí)現(xiàn)
1、實(shí)現(xiàn)裝飾器
由于Adorner是一個(gè)抽象類不能直接實(shí)現(xiàn),所有我們需要定義一個(gè)子類實(shí)現(xiàn)并它。
class NormalAdorner : Adorner
{
/// <summary>
/// 構(gòu)造方法
/// </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、定義附加屬性
通過(guò)propa快捷定義一個(gè)名稱為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、加入裝飾層
在附加屬性改變事件中,進(jìn)行裝飾層的添加。
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("獲取控件裝飾層失敗,控件可能沒(méi)有裝飾層!");
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("獲取控件裝飾層失敗,控件可能沒(méi)有裝飾層!");
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>
/// 構(gòu)造方法
/// </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>
效果預(yù)覽

總結(jié)
以上就是今天要講的內(nèi)容,在界面上定義裝飾器主要目的是為了方編寫(xiě)復(fù)雜樣式,使用方式有了較大的變化。想要靈活使用則需要對(duì)wpf有一定的深入了解。但從另外一個(gè)角度來(lái)說(shuō)在界面上定義裝飾器和使用Grid布局調(diào)整層疊達(dá)到相同效果,可能本質(zhì)上區(qū)別不太大,至少在控件樹(shù)上兩者是一模一樣的??偟膩?lái)說(shuō)個(gè)人覺(jué)得這是一種比較有意思的裝飾器使用方法。
到此這篇關(guān)于C# wpf利用附加屬性實(shí)現(xiàn)界面上定義裝飾器的文章就介紹到這了,更多相關(guān)C# wpf界面定義裝飾器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之
相關(guān)文章
C#統(tǒng)計(jì)C、C++及C#程序代碼行數(shù)的方法
這篇文章主要介紹了C#統(tǒng)計(jì)C、C++及C#程序代碼行數(shù)的方法,較為詳細(xì)的分析了C#統(tǒng)計(jì)文本文件的原理與相關(guān)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08
C#中ListView控件實(shí)現(xiàn)窗體代碼
這篇文章主要介紹了C#中ListView控件實(shí)現(xiàn)窗體的核心代碼,非常不錯(cuò),具有參考借鑒價(jià)值,對(duì)c#listview相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-08-08

