C# wpf利用Clip属性实现截屏框

这篇具有很好参考价值的文章主要介绍了C# wpf利用Clip属性实现截屏框。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

wpf截屏系列

第一章 使用GDI+实现截屏
第二章 制作截屏框(本章)
______第一节 使用DockPanel制作截屏框
______第二节 利用Clip属性实现截屏框(本节)
第三章 实现截屏框热键截屏
第四章 实现截屏框实时截屏
第五章 使用ffmpeg命令行实现录屏



前言

第一节已经实现过截屏框,实现方法相对简单,也仅支持矩形框。最近使用wpf的clip时发现了一种用法,可以实现穿透效果。那显然我们基于clip也能实现截屏窗口,而且支持任意形状。


一、实现步骤

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" />
                <!--上层形状即为穿透区域-->
                <RectangleGeometry x:Name="foreRect" Rect="0 0 200 200" RadiusX="100" RadiusY="100"/>
            </GeometryGroup>
        </Grid.Clip>
    </Grid>
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text= "Clip区域会穿透" Foreground="Black"></TextBlock>
</Grid>

C# wpf利用Clip属性实现截屏框,# wpf,c#,wpf,开发语言

2、子控件同步Clip区域

单纯Clip无法实现拖动和改变大小,尤其是改变大小直接通过鼠标事件结合clip也不好实现。比较简单的方法是定义一个子控件,子控件的位置和大小与Clip关联,这样只要实现子控件的拖动和调整大小功能就能控制Clip区域了。
通过LayoutUpdated事件就可以实时同步Clip区域。子控件就相当于截屏框。

<Border x:Name="clipBorder" LayoutUpdated="Border_LayoutUpdated">

下列代码的GetPosition是自定义拓展方法,自己实现获取控件坐标即可。

private void Border_LayoutUpdated(object sender, EventArgs e)
{
    //截屏框与上层clip rect保持一致
    foreRect.Rect = new Rect(clipBorder.GetPosition(), new Size(clipBorder.ActualWidth, clipBorder.ActualHeight));;
}

3、子控件实现拖动

参考《wpf拖动系列》,根据不同的容器选择不同实现(直接拷贝网页代码),此处使用第六章的功能简化实现。

<Border x:Name="clipBorder" ac:Move.IsDragMoveable="True" >

4、子控件实现拖动调整大小

参考《wpf拖动调整大小系列》,根据不同的容器选择不同实现(直接拷贝网页代码),此处使用第五章的功能简化实现。

<Border x:Name="clipBorder" ac:Resize.IsDragResizeable="True" >

5、鼠标事件传递

由于使用了Clip穿透,穿透区域的子控件是无法响应鼠标的,有幸的是穿透区域不会影响装饰层,所以我们需要在子控件里定义一个装饰器用于捕获鼠标消息。我们通过《wpf 附加属性实现界面上定义装饰器》简化装饰器的定义。

<Border x:Name="clipBorder">
    <!--截屏框的装饰层,用于捕获鼠标消息-->
    <local:AdornerHelper.AdornerContent>
        <Grid MouseDown="Grid_MouseDown" Background="Transparent"></Grid>
    </local:AdornerHelper.AdornerContent>
</Border>
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{  
     //事件转移,触发拖动
    clipBorder.RaiseEvent(e);
}

二、完整代码

1、自行整合

通过上述步骤,将《wpf拖动系列》、《wpf拖动调整大小系列》、《wpf 附加属性实现界面上定义装饰器》网页上的代码(对应容器类型)整合到一起即可实现所有功能。

2、简化的实现

下列是使用wpf拖动系列第六章和wpf拖动调整大小系列第五章的实现,需要下载。
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实现穿透-->
            <GeometryGroup  FillRule="EvenOdd">
                <RectangleGeometry x:Name="backRect"/>
                <!--实际的截屏形状-->
                <RectangleGeometry x:Name="foreRect"  />
            </GeometryGroup>
        </Grid.Clip>
        <!--截屏框-->
        <Border x:Name="clipBorder" Width="200" Height="200" ac:Move.IsDragMoveable="True" ac:Resize.IsDragResizeable="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>
            <!--截屏框的装饰层,用于捕获鼠标消息-->
            <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)
        {  
             //事件转移,触发拖动
            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>
            /// 构造方法
            /// </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;
            }

        }
    }
}

三、效果预览

我们可以通过设置foreRect的类型改变形状,当然Border_LayoutUpdated的逻辑也要相应的修改。

1、矩形框

C# wpf利用Clip属性实现截屏框,# wpf,c#,wpf,开发语言

2、圆形框

C# wpf利用Clip属性实现截屏框,# wpf,c#,wpf,开发语言


总结

以上就是今天要讲的内容,有了之前的基础本文实现起来相对容易,当前目前的也是比较初步的功能,但灵活性是比DockPanel要好的,尤其是支持任意形状,这样就有利于后期划线截屏的实现了。文章来源地址https://www.toymoban.com/news/detail-817617.html

到了这里,关于C# wpf利用Clip属性实现截屏框的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java】后端开发语言Java和C#,两者对比注解和属性的区别以及作用

    欢迎来到《小5讲堂》 大家好,我是全栈小5。 这是《Java》序列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对知识点的理解和掌握。 温馨提示:博主能力有限,理解水平有限

    2024年01月16日
    浏览(44)
  • C#创建DataTable并填充数据,按钮事件实现全选,并到全选的值。wpf开发

    wpf开发中,用事件创建一个datatable度填充到datagird里面,在datagrid里面有第一列是复选框。用一单击事件实现全选,用一个按钮事件得到所选中的值。 Window x:Class=\\\"WpfApp4.MainWindow\\\"         xmlns=\\\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\\\"         xmlns:x=\\\"http://schemas.microsoft.com

    2024年02月08日
    浏览(29)
  • css 属性 clip-path:polygon实现任意图形、多边形

    最近画看板,要求点击客户自定义的不规则图形内的任意地方都可以展示相应的提示, 刚开始让UI 提供切好的不规则背景图,切换位置替换不同的图形,判断是哪个图展示对应的提示 后来查到css这个属性,太好用了 clip-path CSS 属性使用裁剪方式创建元素的可显示区域,类似

    2024年02月12日
    浏览(30)
  • [C#]Onnxruntime部署Chinese CLIP实现以文搜图以文找图功能

    【官方框架地址】 https://github.com/OFA-Sys/Chinese-CLIP 【算法介绍】 在当今的大数据时代,文本信息处理已经成为了计算机科学领域的核心议题之一。为了高效地处理海量的文本数据,自然语言处理(NLP)技术应运而生。而在诸多NLP技术中,文本分割是一种基础且重要的任务。

    2024年02月02日
    浏览(26)
  • Winform/WPF利用CefSharp集成vue开发

    有时候因为各种原因,可能在开发winform或wpf项目的时候需要嵌入web项目,而目前vue在web开发中还是非常流行的,今天有空琢磨了一下怎么在winform中集成vue进行开发,当然,winform能实现,wpf也是一样的。 目前希望达到的效果是,能够在winform中显示web界面,并且能够与vue中的

    2024年02月08日
    浏览(31)
  • C# WPF上位机开发(键盘绘图控制)

    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】         在软件开发中,如果存在canvas图像的话,一般有几种控制方法。一种是鼠标控制;一种是键盘控制;还有一种是定时器控制。定时器控制,多常见动画、游戏、3d视频当中。而鼠标控制

    2024年02月02日
    浏览(32)
  • C#开发winform&wpf后台捕获鼠标移动事件

    做 WPF和winform的时候,可以在界面上设置鼠标移动事件来检测鼠标移动,如果项目为后期改造这样做的话改动量很大,今天通过另外一种后台调用windows api的方式进行快速捕获和触发,提高开发效率分享给大家。

    2024年02月16日
    浏览(36)
  • C# WPF上位机开发(Web API联调)

    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】         很多时候,客户需要开发的不仅仅是一个上位机系统,它还有其他很多配套的系统或设备,比如物流小车、立库、数字孪生等一整套系统。这个时候,上位机系统就需要和各个子系统

    2024年01月20日
    浏览(28)
  • WPF-利用装饰器实现控件的自由拖动

    在项目中经常会遇到类似如下要求的需求,创建允许自由拖动的控件,这样的需求可以使用WPF的装饰器Adorner来实现。   装饰器是一种特殊类型的FrameworkElement,装饰器始终呈现在被装饰元素的顶部,用于向用户提供可视化提示。装饰器可以在不改变原有控件结构的基础上,将

    2024年02月11日
    浏览(33)
  • WPF-利用装饰器实现空间的自由拖动

    在项目中经常会遇到类似如下要求的需求,创建允许自由拖动的控件,这样的需求可以使用WPF的装饰器Adorner来实现。   装饰器是一种特殊类型的FrameworkElement,装饰器始终呈现在被装饰元素的顶部,用于向用户提供可视化提示。装饰器可以在不改变原有控件结构的基础上,将

    2024年02月11日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包