C# WPF利用Clip屬性實(shí)現(xiàn)截屏框功能
前言
第一節(jié)已經(jīng)實(shí)現(xiàn)過(guò)截屏框,實(shí)現(xiàn)方法相對(duì)簡(jiǎn)單,也僅支持矩形框。最近使用wpf的clip時(shí)發(fā)現(xiàn)了一種用法,可以實(shí)現(xiàn)穿透效果。那顯然我們基于clip也能實(shí)現(xiàn)截屏窗口,而且支持任意形狀。
一、實(shí)現(xiàn)步驟
1、Clip穿透
使用GeometryGroup 且FillRule為EvenOdd就可以做出穿透的效果。
<Grid> <Grid Width="200" Height="200" Background="SeaGreen" > <Grid.Clip> <GeometryGroup FillRule="EvenOdd"> <!--底下的rect必須保持和容器大小一致--> <RectangleGeometry Rect="0 0 200 200" /> <!--上層形狀即為穿透區(qū)域--> <RectangleGeometry x:Name="foreRect" Rect="0 0 200 200" RadiusX="100" RadiusY="100"/> </GeometryGroup> </Grid.Clip> </Grid> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text= "Clip區(qū)域會(huì)穿透" Foreground="Black"></TextBlock> </Grid>
2、子控件同步Clip區(qū)域
單純Clip無(wú)法實(shí)現(xiàn)拖動(dòng)和改變大小,尤其是改變大小直接通過(guò)鼠標(biāo)事件結(jié)合clip也不好實(shí)現(xiàn)。比較簡(jiǎn)單的方法是定義一個(gè)子控件,子控件的位置和大小與Clip關(guān)聯(lián),這樣只要實(shí)現(xiàn)子控件的拖動(dòng)和調(diào)整大小功能就能控制Clip區(qū)域了。
通過(guò)LayoutUpdated事件就可以實(shí)時(shí)同步Clip區(qū)域。子控件就相當(dāng)于截屏框。
<Border x:Name="clipBorder" LayoutUpdated="Border_LayoutUpdated">
下列代碼的GetPosition是自定義拓展方法,自己實(shí)現(xiàn)獲取控件坐標(biāo)即可。
private void Border_LayoutUpdated(object sender, EventArgs e) { //截屏框與上層clip rect保持一致 foreRect.Rect = new Rect(clipBorder.GetPosition(), new Size(clipBorder.ActualWidth, clipBorder.ActualHeight));; }
3、子控件實(shí)現(xiàn)拖動(dòng)
參考《wpf拖動(dòng)系列》,根據(jù)不同的容器選擇不同實(shí)現(xiàn)(直接拷貝網(wǎng)頁(yè)代碼),此處使用第六章的功能簡(jiǎn)化實(shí)現(xiàn)。
<Border x:Name="clipBorder" ac:Move.IsDragMoveable="True" >
4、子控件實(shí)現(xiàn)拖動(dòng)調(diào)整大小
參考《wpf拖動(dòng)調(diào)整大小系列》,根據(jù)不同的容器選擇不同實(shí)現(xiàn)(直接拷貝網(wǎng)頁(yè)代碼),此處使用第五章的功能簡(jiǎn)化實(shí)現(xiàn)。
<Border x:Name="clipBorder" ac:Resize.IsDragResizeable="True" >
5、鼠標(biāo)事件傳遞
由于使用了Clip穿透,穿透區(qū)域的子控件是無(wú)法響應(yīng)鼠標(biāo)的,有幸的是穿透區(qū)域不會(huì)影響裝飾層,所以我們需要在子控件里定義一個(gè)裝飾器用于捕獲鼠標(biāo)消息。我們通過(guò)《wpf 附加屬性實(shí)現(xiàn)界面上定義裝飾器》簡(jiǎn)化裝飾器的定義。
<Border x:Name="clipBorder"> <!--截屏框的裝飾層,用于捕獲鼠標(biāo)消息--> <local:AdornerHelper.AdornerContent> <Grid MouseDown="Grid_MouseDown" Background="Transparent"></Grid> </local:AdornerHelper.AdornerContent> </Border>
private void Grid_MouseDown(object sender, MouseButtonEventArgs e) { //事件轉(zhuǎn)移,觸發(fā)拖動(dòng) clipBorder.RaiseEvent(e); }
二、完整代碼
1、自行整合
通過(guò)上述步驟,將《wpf拖動(dòng)系列》、《wpf拖動(dòng)調(diào)整大小系列》、《wpf 附加屬性實(shí)現(xiàn)界面上定義裝飾器》網(wǎng)頁(yè)上的代碼(對(duì)應(yīng)容器類型)整合到一起即可實(shí)現(xiàn)所有功能。
2、簡(jiǎn)化的實(shí)現(xiàn)
下列是使用wpf拖動(dòng)系列第六章和wpf拖動(dòng)調(diào)整大小系列第五章的實(shí)現(xiàn),需要下載。
xaml
<Window x:Class="WpfClip.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:WpfClip" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" WindowStyle="None" Background="Transparent" ResizeMode="NoResize" Topmost="True" WindowState="Maximized" Title="MainWindow" Height="450" Width="800"> <WindowChrome.WindowChrome> <WindowChrome GlassFrameThickness="-1" CaptionHeight="0" /> </WindowChrome.WindowChrome > <Grid x:Name="grid" Background="#80000000" LayoutUpdated="Grid_LayoutUpdated"> <Grid.Clip> <!--利用clip實(shí)現(xiàn)穿透--> <GeometryGroup FillRule="EvenOdd"> <RectangleGeometry x:Name="backRect"/> <!--實(shí)際的截屏形狀--> <RectangleGeometry x:Name="foreRect" /> </GeometryGroup> </Grid.Clip> <!--截屏框--> <Border x:Name="clipBorder" Width="200" Height="200" ac:Move.IsDragMoveable="True" ac:Resize.IsResizeable="True" LayoutUpdated="Border_LayoutUpdated"> <ac:Resize.ThumbsTemplate> <ControlTemplate> <Border Width="16" Height="16" Background=" Green" BorderBrush="White" BorderThickness="2" CornerRadius="8"></Border> </ControlTemplate> </ac:Resize.ThumbsTemplate> <ac:Resize.ThumbsPanel> <ItemsPanelTemplate> <Grid Margin="-8"></Grid> </ItemsPanelTemplate> </ac:Resize.ThumbsPanel> <!--截屏框的裝飾層,用于捕獲鼠標(biāo)消息--> <local:AdornerHelper.AdornerContent> <Grid MouseDown="Grid_MouseDown" Background="Transparent"></Grid> </local:AdornerHelper.AdornerContent> </Border> </Grid> </Window>
cs
using AC; using System.Windows; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; namespace WpfClip { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Grid_LayoutUpdated(object sender, EventArgs e) { //確保底層clip rect與容器大小相同 backRect.Rect=new Rect(0,0, grid.ActualWidth, grid.ActualHeight); } private void Border_LayoutUpdated(object sender, EventArgs e) { //截屏框與上層clip rect保持一致 foreRect.Rect = new Rect(clipBorder.GetPosition(), new Size(clipBorder.ActualWidth, clipBorder.ActualHeight)); //圓形效果,去掉則是矩形 foreRect.RadiusX = clipBorder.Width/2; foreRect.RadiusY= clipBorder.Height/2; } private void Grid_MouseDown(object sender, MouseButtonEventArgs e) { //事件轉(zhuǎn)移,觸發(fā)拖動(dòng) clipBorder.RaiseEvent(e); } } 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; } } } }
三、效果預(yù)覽
我們可以通過(guò)設(shè)置foreRect的類型改變形狀,當(dāng)然Border_LayoutUpdated的邏輯也要相應(yīng)的修改。
1、矩形框
2、圓形框
總結(jié)
有了之前的基礎(chǔ)本文實(shí)現(xiàn)起來(lái)相對(duì)容易,當(dāng)前目前的也是比較初步的功能,但靈活性是比DockPanel要好的,尤其是支持任意形狀,這樣就有利于后期劃線截屏的實(shí)現(xiàn)了。
到此這篇關(guān)于C# WPF利用Clip屬性實(shí)現(xiàn)截屏框功能的文章就介紹到這了,更多相關(guān)C# WPF截屏框內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#創(chuàng)建SQLite控制臺(tái)應(yīng)用程序詳解
這篇文章主要為大家詳細(xì)介紹了C#創(chuàng)建SQLite控制臺(tái)應(yīng)用程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07使用C#與SQL Server數(shù)據(jù)庫(kù)進(jìn)行交互的詳細(xì)步驟
在C#中與數(shù)據(jù)庫(kù)進(jìn)行交互,通常使用ADO.NET(ActiveX Data Objects .NET)框架,ADO.NET是.NET Framework中用于數(shù)據(jù)訪問(wèn)的一組類庫(kù),它提供了多種用于連接和操作數(shù)據(jù)庫(kù)的方法,以下是使用C#與SQL Server數(shù)據(jù)庫(kù)進(jìn)行交互的詳細(xì)步驟,需要的朋友可以參考下2024-08-08C#使用JArray和JObject封裝JSON對(duì)象
這篇文章介紹了C#使用JArray和JObject封裝JSON對(duì)象的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07整理C# 二進(jìn)制,十進(jìn)制,十六進(jìn)制 互轉(zhuǎn)
c#下進(jìn)制互轉(zhuǎn)代碼2008-10-10C#實(shí)現(xiàn)兩接口中同名方法實(shí)例分析
這篇文章主要介紹了C#實(shí)現(xiàn)兩接口中同名方法,涉及C#接口與方法的相關(guān)操作技巧,需要的朋友可以參考下2015-05-05在C#中使用二叉樹(shù)實(shí)時(shí)計(jì)算海量用戶積分排名的實(shí)現(xiàn)詳解
這篇文章主要介紹了在C#中使用二叉樹(shù)實(shí)時(shí)計(jì)算海量用戶積分排名的實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01