C# WPF利用Clip屬性實(shí)現(xiàn)截屏框功能
前言
第一節(jié)已經(jīng)實(shí)現(xiàn)過截屏框,實(shí)現(xià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無法實(shí)現(xiàn)拖動(dòng)和改變大小,尤其是改變大小直接通過鼠標(biāo)事件結(jié)合clip也不好實(shí)現(xiàn)。比較簡單的方法是定義一個(gè)子控件,子控件的位置和大小與Clip關(guān)聯(lián),這樣只要實(shí)現(xiàn)子控件的拖動(dòng)和調(diào)整大小功能就能控制Clip區(qū)域了。
通過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)頁代碼),此處使用第六章的功能簡化實(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)頁代碼),此處使用第五章的功能簡化實(shí)現(xiàn)。
<Border x:Name="clipBorder" ac:Resize.IsDragResizeable="True" >
5、鼠標(biāo)事件傳遞
由于使用了Clip穿透,穿透區(qū)域的子控件是無法響應(yīng)鼠標(biāo)的,有幸的是穿透區(qū)域不會(huì)影響裝飾層,所以我們需要在子控件里定義一個(gè)裝飾器用于捕獲鼠標(biāo)消息。我們通過《wpf 附加屬性實(shí)現(xià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、自行整合
通過上述步驟,將《wpf拖動(dòng)系列》、《wpf拖動(dòng)調(diào)整大小系列》、《wpf 附加屬性實(shí)現(xiàn)界面上定義裝飾器》網(wǎng)頁上的代碼(對應(yīng)容器類型)整合到一起即可實(shí)現(xiàn)所有功能。
2、簡化的實(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("獲取控件裝飾層失敗,控件可能沒有裝飾層!");
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>
/// 構(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ù)覽
我們可以通過設(shè)置foreRect的類型改變形狀,當(dāng)然Border_LayoutUpdated的邏輯也要相應(yīng)的修改。
1、矩形框

2、圓形框

總結(jié)
有了之前的基礎(chǔ)本文實(shí)現(xiàn)起來相對容易,當(dāng)前目前的也是比較初步的功能,但靈活性是比DockPanel要好的,尤其是支持任意形狀,這樣就有利于后期劃線截屏的實(shí)現(xiàn)了。
到此這篇關(guān)于C# WPF利用Clip屬性實(shí)現(xiàn)截屏框功能的文章就介紹到這了,更多相關(guān)C# WPF截屏框內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 使用C#從零開始實(shí)現(xiàn)一個(gè)截屏工具
- 使用C#自制一個(gè)截屏工具
- C#?WPF使用GDI實(shí)現(xiàn)截屏功能
- C#?wpf實(shí)現(xiàn)截屏框熱鍵截屏的示例代碼
- C#?wpf使用GDI+實(shí)現(xiàn)截屏效果
- C#?wpf使用DockPanel實(shí)現(xiàn)制作截屏框
- 通過C#編寫一個(gè)簡易的Windows截屏增強(qiáng)工具
- C#實(shí)現(xiàn)小截屏軟件功能
- 基于C#實(shí)現(xiàn)的屏幕指定區(qū)域截屏代碼
- c#不使用系統(tǒng)api實(shí)現(xiàn)可以指定區(qū)域屏幕截屏功能
- c#根據(jù)網(wǎng)址抓取網(wǎng)頁截屏生成圖片的示例
- C# 全屏截圖的功能實(shí)現(xiàn)
相關(guān)文章
使用C#調(diào)用百度地圖并實(shí)現(xiàn)坐標(biāo)點(diǎn)的設(shè)置以及讀取示例
這篇文章主要介紹了使用C#調(diào)用百度地圖并實(shí)現(xiàn)坐標(biāo)點(diǎn)的設(shè)置以及讀取示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
C#中Prism框架的SetRegionManager用法詳解
這篇文章主要介紹了C#中SetRegionManager的正確使用方法,避免常見誤區(qū),如未正確注入IRegionManager、重復(fù)設(shè)置RegionManager等錯(cuò)誤,深入了解Prism框架中的區(qū)域管理技巧,需要的朋友可以參考下2026-06-06
C#中Winform 實(shí)現(xiàn)Ajax效果自定義按鈕
這篇文章主要介紹了C#中Winform 實(shí)現(xiàn)Ajax效果自定義按鈕的相關(guān)資料,需要的朋友可以參考下2017-12-12
淺析C#中的Main(String[] args)參數(shù)輸入問題
本篇文章主要是對C#中的Main(String[] args)參數(shù)輸入問題進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01
通過C#和RTSPClient實(shí)現(xiàn)簡易音視頻解碼功能
在多媒體應(yīng)用中,實(shí)時(shí)傳輸協(xié)議(RTSP)用于流媒體服務(wù),特別是音視頻?監(jiān)控系統(tǒng),通過?C#?和?RTSPClient?庫,可以輕松實(shí)現(xiàn)簡易的音視頻解碼和播放功能,本文將詳細(xì)介紹如何使用?C#?和?RTSPClient?構(gòu)建一個(gè)簡易但高效的音視頻解碼器,需要的朋友可以參考下2024-12-12

