前言

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

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. python常用内置函数和关键字

    常用内置方法 在Python中有许许多多的内置方法,就是一些Python内置的函数,它们是我们日常中经常可以使用的到的一些基础的工具,可以方便我们的工作. 查看所有的内置类和内置方法 # 方法一 bu ...

  2. 27个常用Linux命令

    1.查找文件 find / -name filename.txt 根据名称查找/目录下的filename.txt文件. 2.查看一个程序是否运行 ps –ef|grep tomcat 查看所有有关to ...

  3. 软件项目管理 ——1.2.PMBOK与软件项目管理知识体系

    软件项目管理 --1.2.PMBOK与软件项目管理知识体系 归档于软件项目管理初级学习路线 第一章 软件项目管理基本概念 <初级学习路线合集 > @ 目录 软件项目管理 --1.2.PMB ...

  4. 好客租房9-jsx的学习目标

    1能够知道什么是jsx 2能够使用jsx创建react元素 3能够在jsx使用javascript表达式 4能够使用jsx的条件渲染和列表渲染 5能够给jsx添加样式 jsx的基本使用 jsx中使用j ...

  5. java-去除html中的标签或者元素属性(正则表达式/jsoup)

    业务场景: 如一篇使用富文本编辑器编辑的新闻稿,需要在列表页面截取前200字作为摘要,此时需要去除html标签,截取真正的文本部分. /** * 删除Html标签 */public static St ...

  6. JavaDoc——JavaSE基础

    JavaDoc 文档注释内容的含义 @author // 作者 @version // 版本 @since // 最早支持的Java版本 @param // 接收的参数 @return // 返回值 ...

  7. 关于kali安装输入法

    之前老是被kali大小写输入恶心坏了,正好看到一篇文章写kali安装搜狗输入法的,虽然不需要输入中文,但是英文输入就很方便了. 一.切换root用户登录 1.sodu su切换为root权限 2.pa ...

  8. 针对elementUI 中InfiniteScroll按需引入的一点注意事项

    大家为了节省空间,常常进行按需引入来节省空间,这里我给大家来介绍一下element中按需引入无限滚动指令注意的事项. 针对前面element 按需引入的一些配置这里就不再详细介绍了. 那么这里讲的是在 ...

  9. 自己封装的tools.js文件

    /* * 生成指定范围的随机整数 * @param lower 下限 * @param upper 上限 * @return 返回指定范围的随机整数,上/下限值均可取 */ function rand ...

  10. SAP -熟练使用T-Code SHD0

    SHD0 业务顾问和开发顾问都非常熟悉的一个T-Code, 如果能合理使用它,可以省去许多增强和程序修改工作. 当我需要时,我在这里找不到任何相关文档,这就是为什么我想借此机会向我们自己的SCN提供内 ...