前言

接着上周写的截图控件继续更新 绘制方框与椭圆

1.WPF实现截屏「仿微信」

2.WPF 实现截屏控件之移动(二)「仿微信」

3.WPF 截图控件之伸缩(三) 「仿微信」

正文

有开发者在B站反馈第三篇有Issues已修复。

实现在截图区域内绘制 方框椭圆 有两种方式

1)可以在截图的区域内部添加一个Canvas宽高填充至区域内,在进行绘制方框或椭圆。

2)直接在外层的Canvas中添加,这样需要判断鼠标按下的位置和移动的位置必须在已截图区域内,如超出范围也不绘制到区域外。

本章使用了第二种方式

此篇更新截图时隐藏当前窗口

一、首先接着ScreenCut继续发电。

1.1

新增定义 画方框、椭圆、颜色选择框Popup、Popup内部Border、Border内部RadioButton的父容器

     [TemplatePart(Name = RadioButtonRectangleTemplateName, Type = typeof(RadioButton))]
[TemplatePart(Name = RadioButtonEllipseTemplateName, Type = typeof(RadioButton))]
[TemplatePart(Name = PopupTemplateName, Type = typeof(Popup))]
[TemplatePart(Name = PopupBorderTemplateName, Type = typeof(Border))]
[TemplatePart(Name = WrapPanelColorTemplateName, Type = typeof(WrapPanel))] private const string RadioButtonRectangleTemplateName = "PART_RadioButtonRectangle";
private const string RadioButtonEllipseTemplateName = "PART_RadioButtonEllipse";
private const string PopupTemplateName = "PART_Popup";
private const string PopupBorderTemplateName = "PART_PopupBorder";
private const string WrapPanelColorTemplateName = "PART_WrapPanelColor";
private Popup _popup;
private WrapPanel _wrapPanel; /// <summary>
/// 当前绘制矩形
/// </summary>
private Border borderRectangle;
/// <summary>
/// 绘制当前椭圆
/// </summary>
private Ellipse drawEllipse;
/// <summary>
/// 当前选择颜色
/// </summary>
private Brush _currentBrush;

1.2

新增RadioButtonStyles为了选择方框、椭圆、颜色

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Basic/ControlBasic.xaml"/>
</ResourceDictionary.MergedDictionaries> <Style x:Key="PathRadioButton" TargetType="{x:Type RadioButton}" BasedOn="{StaticResource ControlBasicStyle}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="FrameworkElement.OverridesDefaultStyle" Value="True" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="8" />
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<Border Background="Transparent">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
x:Name="PART_ContentPresenter" Opacity=".8"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Opacity" TargetName="PART_ContentPresenter" Value="1"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" TargetName="PART_ContentPresenter" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style x:Key="ColorRadioButton" TargetType="{x:Type RadioButton}" BasedOn="{StaticResource ControlBasicStyle}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="FrameworkElement.OverridesDefaultStyle" Value="True" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Padding" Value="8" />
<Setter Property="Width" Value="15"/>
<Setter Property="Height" Value="15"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<Border Background="{TemplateBinding Background}"
BorderThickness="0"
x:Name="PART_Border"
CornerRadius="7"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
Storyboard.TargetName="PART_Ellipse">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked" />
<VisualState x:Name="Indeterminate" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse x:Name="PART_Ellipse"
Width="7"
Height="7"
Fill="{DynamicResource WhiteSolidColorBrush}"
Visibility="Collapsed"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value=".8"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> </ResourceDictionary>

1.3

ScreenCut.xaml增加代码如下


<RadioButton x:Name="PART_RadioButtonRectangle"
Style="{DynamicResource PathRadioButton}"
ToolTip="方框"
Margin="4,0">
<RadioButton.Content>
<Path Fill="{DynamicResource RegularTextSolidColorBrush}"
Width="18" Height="18" Stretch="Fill"
Data="{StaticResource PathRectangle}"/>
</RadioButton.Content>
</RadioButton>
<RadioButton x:Name="PART_RadioButtonEllipse"
Style="{DynamicResource PathRadioButton}"
ToolTip="椭圆"
Margin="4,0">
<ToggleButton.Content>
<Ellipse Width="19" Height="19"
StrokeThickness="1.5"
SnapsToDevicePixels="True"
UseLayoutRounding="True"
Stroke="{DynamicResource RegularTextSolidColorBrush}"/>
</ToggleButton.Content>
</RadioButton> <Popup x:Name="PART_Popup"
AllowsTransparency="True"
Placement="Bottom"
VerticalOffset="13">
<Border Effect="{DynamicResource PopupShadowDepth}"
Background="{DynamicResource WhiteSolidColorBrush}"
Margin="10,30,10,10"
CornerRadius="{Binding Path=(helpers:ControlsHelper.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}"
x:Name="PART_PopupBorder">
<Grid>
<Path Data="{StaticResource PathUpperTriangle}"
Fill="{DynamicResource WhiteSolidColorBrush}"
Stretch="Uniform"
Width="10" VerticalAlignment="Top"
Margin="0,-8,0,0"
SnapsToDevicePixels="True"
UseLayoutRounding="True"/>
<WrapPanel Margin="10"
VerticalAlignment="Center"
x:Name="PART_WrapPanelColor">
<RadioButton Style="{DynamicResource ColorRadioButton}"
Margin="4,0" Background="Red"
IsChecked="True">
</RadioButton>
<RadioButton Style="{DynamicResource ColorRadioButton}"
Margin="4,0"
Background="DodgerBlue">
</RadioButton>
</WrapPanel>
</Grid>
</Border>
</Popup>

二、ScreenCut.cs 增加的后台逻辑如下

2.1 RadioButton选中方框和椭圆的切换Popup并设置ScreenCutMouseType枚举和鼠标:

    _radioButtonRectangle = GetTemplateChild(RadioButtonRectangleTemplateName) as RadioButton;
if (_radioButtonRectangle != null)
_radioButtonRectangle.Click += _radioButtonRectangle_Click;
_radioButtonEllipse = GetTemplateChild(RadioButtonEllipseTemplateName) as RadioButton;
if (_radioButtonEllipse != null)
_radioButtonEllipse.Click += _radioButtonEllipse_Click;
private void _radioButtonRectangle_Click(object sender, RoutedEventArgs e)
{
RadioButtonChecked(_radioButtonRectangle, ScreenCutMouseType.DrawRectangle);
}
private void _radioButtonEllipse_Click(object sender, RoutedEventArgs e)
{
RadioButtonChecked(_radioButtonEllipse, ScreenCutMouseType.DrawEllipse);
}
void RadioButtonChecked(RadioButton radioButton, ScreenCutMouseType screenCutMouseTypeRadio)
{
if (radioButton.IsChecked == true)
{
screenCutMouseType = screenCutMouseTypeRadio;
_border.Cursor = Cursors.Arrow;
if (_popup.PlacementTarget != null && _popup.IsOpen)
_popup.IsOpen = false;
_popup.PlacementTarget = radioButton;
_popup.IsOpen = true;
}
else
{
if (screenCutMouseType == screenCutMouseTypeRadio)
Restore(); }
}
void Restore()
{
_border.Cursor = Cursors.SizeAll;
if (screenCutMouseType == ScreenCutMouseType.Default) return;
screenCutMouseType = ScreenCutMouseType.Default;
}

2.2 ScreenCut绘制方框和椭圆代码如下:

void DrawMultipleControl(Point current)
{
if (current == pointStart) return; if (current.X > rect.BottomRight.X
||
current.Y > rect.BottomRight.Y)
return;
var drawRect = new Rect(pointStart, current);
switch (screenCutMouseType)
{
case ScreenCutMouseType.DrawRectangle:
if (borderRectangle == null)
{
borderRectangle = new Border()
{
BorderBrush = _currentBrush == null ? Brushes.Red : _currentBrush,
BorderThickness = new Thickness(3),
CornerRadius = new CornerRadius(3),
};
_canvas.Children.Add(borderRectangle);
}
break;
case ScreenCutMouseType.DrawEllipse:
if (drawEllipse == null)
{
drawEllipse = new Ellipse()
{
Stroke = _currentBrush == null ? Brushes.Red : _currentBrush,
StrokeThickness = 3,
};
_canvas.Children.Add(drawEllipse);
}
break; } var _borderLeft = drawRect.Left - Canvas.GetLeft(_border); if (_borderLeft < 0)
_borderLeft = Math.Abs(_borderLeft);
if (drawRect.Width + _borderLeft < _border.ActualWidth)
{
var wLeft = Canvas.GetLeft(_border) + _border.ActualWidth;
var left = drawRect.Left < Canvas.GetLeft(_border) ? Canvas.GetLeft(_border) : drawRect.Left > wLeft ? wLeft : drawRect.Left;
if (borderRectangle != null)
{
borderRectangle.Width = drawRect.Width;
Canvas.SetLeft(borderRectangle, left);
}
if (drawEllipse != null)
{
drawEllipse.Width = drawRect.Width;
Canvas.SetLeft(drawEllipse, left);
} } var _borderTop = drawRect.Top - Canvas.GetTop(_border);
if(_borderTop < 0)
_borderTop = Math.Abs(_borderTop);
if (drawRect.Height + _borderTop < _border.ActualHeight)
{
var hTop = Canvas.GetTop(_border) + _border.Height;
var top = drawRect.Top < Canvas.GetTop(_border) ? Canvas.GetTop(_border) : drawRect.Top > hTop ? hTop : drawRect.Top;
if (borderRectangle != null)
{
borderRectangle.Height = drawRect.Height;
Canvas.SetTop(borderRectangle, top);
} if (drawEllipse != null)
{
drawEllipse.Height = drawRect.Height;
Canvas.SetTop(drawEllipse, top);
} }
}

2.3 Popup跟随问题这里解决办法是先关闭再打开代码如下:

 if (_popup != null && _popup.IsOpen)
{
_popup.IsOpen = false;
_popup.IsOpen = true;
}

2.4 ScreenCut使用方式如下:

 public partial class ScreenCutExample : UserControl
{
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
} public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof(bool), typeof(ScreenCutExample), new PropertyMetadata(false)); public ScreenCutExample()
{
InitializeComponent();
} private void Button_Click(object sender, RoutedEventArgs e)
{
var screenCut = new ScreenCut();
if (IsChecked)
{
App.CurrentMainWindow.WindowState = WindowState.Minimized;
screenCut.Show();
screenCut.Activate();
}
else
screenCut.ShowDialog();
}
}

完整代码如下

项目地址

  • 框架名:WPFDevelopers
  • 作者:WPFDevelopers
  • GitHub
  • Gitee

WPF 截图控件之绘制方框与椭圆(四) 「仿微信」的更多相关文章

  1. WPF 截图控件之绘制箭头(五)「仿微信」

    前言 接着上周写的截图控件继续更新 绘制箭头. 1.WPF实现截屏「仿微信」 2.WPF 实现截屏控件之移动(二)「仿微信」 3.WPF 截图控件之伸缩(三) 「仿微信」 4.WPF 截图控件之绘制方 ...

  2. WPF 截图控件之文字(七)「仿微信」

    前言 接着上周写的截图控件继续更新添加 文字. 1.WPF实现截屏「仿微信」 2.WPF 实现截屏控件之移动(二)「仿微信」 3.WPF 截图控件之伸缩(三) 「仿微信」 4.WPF 截图控件之绘制方 ...

  3. WPF 截图控件之画笔(八)「仿微信」

    前言 接着上周写的截图控件继续更新添加 画笔. 1.WPF实现截屏「仿微信」 2.WPF 实现截屏控件之移动(二)「仿微信」 3.WPF 截图控件之伸缩(三) 「仿微信」 4.WPF 截图控件之绘制方 ...

  4. WPF 截图控件之移除控件(九)「仿微信」

    WPF 截图控件之移除控件(九)「仿微信」 WPF 截图控件之移除控件(九)「仿微信」 作者:WPFDevelopersOrg 原文链接: https://github.com/WPFDevelope ...

  5. WPF常用控件应用demo

    WPF常用控件应用demo 一.Demo 1.Demo截图如下: 2.demo实现过程 总体布局:因放大缩小窗体,控件很根据空间是否足够改变布局,故用WrapPanel布局. <ScrollVi ...

  6. WPF第三方控件盘点

    WPF统一的编程模型.语言和框架,实现了界面设计人员和开发人员工作可以分离的境界,鉴于WPF强大的优势,且一直是开发者关注的地方,下面和大家分享基于WPF项目开发需要用到的第三方控件,包括业界最受好评 ...

  7. WPF开源控件扩展库 - MaterialDesignExtensions

    Material Design Extensions 在WPF开源控件库 Material Design in XAML Toolkit(本站介绍:链接)的基础上进行了控件扩展和特性新增.本开源项目中 ...

  8. C# WPF开源控件库:MahApps.Metro

    其实站长很久之前就知道这个开源WPF控件库了,只是一直欣赏不了这种风格,但也star了该项目.每次浏览该仓库时,发现star越来越多,也看到很多网友对它的褒奖,所以今天就向大家推荐这款WPF控件库. ...

  9. WPF Popup 控件导致被遮挡内容不刷新的原因

    WPF Popup 控件导致被遮挡内容不刷新的原因 周银辉 今天在写一个WPF控件时用到了Popup控件,很郁闷的情况是:当popup关闭时,原来被popup挡住的界面部分不刷新,非要手动刷新一下(比 ...

随机推荐

  1. React 与 Hooks 如何使用 TypeScript 书写类型?

    React 与 Hooks 如何使用 TypeScript 书写类型? 本文写于 2020 年 9 月 20 日 函数组件与 TS 对于 Hooks 来说是不支持使用 class 组件的. 如何在函数 ...

  2. 超级简单!CentOS-8 安装 MySQL 8.0,比喝水还简单

    中国人不骗中国人 果然是系统和MySQL的版本越高安装越便利了 在阿里云的 CentOS-8 比喝开水还简单的安装 MySQL 8.0,开始~ 1.以 root 用户通过 CentOS 软件包管理器来 ...

  3. python读取csv、excel、mysql内容

    前提:导入扩展包 import pandas as pd import pymysql ①读取csv文件 fpath='/test.csv'ratings=pd.read_csv(fpath)prin ...

  4. 『忘了再学』Shell基础 — 25、扩展正则表达式

    目录 1.扩展正则表达式说明 2.练习 (1)+和?练习 (2)|和()练习 3.注意(重点) 1.扩展正则表达式说明 熟悉正则表达式的童鞋应该很疑惑,在其他的语言中是没有扩展正则表达式说法的,在Sh ...

  5. anaconda遇到:Solving environment: failed with initial frozen solve. Retrying with flexible solve.问题

    Solving environment: failed with initial frozen solve. Retrying with flexible solve. 遇到上述问题: 解决方案: # ...

  6. Python参数传递中的 args, kwargs

    概念 真正的Python参数传递语法是*和**,其被称为 被称为打包和解包参数.*args和**kwargs只是大家默认的一种形式.也可以写成*keys和**kkeys等其他形式.二者都是为了在不知道 ...

  7. html关键字大全

    html标签属性大全 html标签属性大全从网上搜集整理的常用html标签,供朋友们交流学习html用. html标签<marquee> <marquee>...</ma ...

  8. Java上传文件至SFTP服务器

    Windows搭建SFTP服务器 https://www.cnblogs.com/wangjunguang/p/9453611.html 注意点: 1.以管理员权限运行FreeSSHd 2.如果无法启 ...

  9. Ubuntu远程桌面助手(URDC)

    目前自动驾驶域控制器项目中使用了英伟达的Orin芯片+Ubuntu20.04系统.域控属于典型的Headless设备,开发调试时需要连接显示器(HDMI/DP).鼠标和键盘,或者使用NoMachine ...

  10. 4.使用CFileDialog打开文件对话框,获得文件路径 -windows编程

    引言:没想到2022年还有很多工业软件公司依然使用MFC,微软也一直在更新MFC的库,这次使用MFC封装的CFileDialog类,写一个获得选定文件路径,名称,扩展名的程序. 个人技术博客(文章整理 ...