前言

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

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. Golang 的 `[]interface{}` 类型

    Golang 的 []interface{} 类型 我其实不太喜欢使用 Go 语言的 interface{} 类型,一般情况下我宁愿多写几个函数:XxxInt, XxxFloat, XxxString ...

  2. 解决 js aysnc await try-catch 地狱

  3. 867. Transpose Matrix - LeetCode

    Question 867. Transpose Matrix Solution 题目大意:矩阵的转置 思路:定义一个转置后的二维数组,遍历原数组,在赋值时行号列号互换即可 Java实现: public ...

  4. 111_Power Pivot 24小时维度:累计、同比、环比相关

    博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 今天有朋友讨论怎么做每天24小时维度的工作量计算(运营类企业,每天24小时都在运营)需求如下: 1.从0时到23 ...

  5. npm删除依赖包

    第一种办法删除全部依赖包 npm uninstall *( 删除指定的依赖包 npm uninstall xxx删除全局的指定依赖 npm uninstall xxx -gxxx为依赖名称)清缓存 n ...

  6. 【SpringCloud原理】Ribbon核心组件以及运行原理万字源码剖析

    大家好,本文我将继续来剖析SpringCloud中负载均衡组件Ribbon的源码.本来我是打算接着OpenFeign动态代理生成文章直接讲Feign是如何整合Ribbon的,但是文章写了一半发现,如果 ...

  7. 关于『进击的Markdown』:第二弹

    关于『进击的Markdown』:第二弹 建议缩放90%食用 众里寻他千百度,蓦然回首,Markdown却在灯火灿烂处 MarkdownYYDS! 各位早上好!  我果然鸽稿了  Markdown 语法 ...

  8. Java集合框架(四)-HashMap

    1.HashMap特点 存放的元素都是键值对(key-value),key是唯一的,value是可以重复的 存放的元素也不保证添加的顺序,即是无序的 存放的元素的键可以为null,但是只能有一个key ...

  9. 一款超级好用的3Dmax模型插件 支持模型多格式批量转换

    对于模型设计师来说模型格式转换是最常见的事,但是每一款建模软件所支持的格式各有不同,模型互导操作太麻烦 为了解决这个难题,老子云平台研发了一款基于3dmax软件的模型格式转换插件,支持多种模型格式想换 ...

  10. OpenCloudOS使用snap安装.NET 6

    开源操作系统社区 OpenCloudOS 由腾讯与合作伙伴共同倡议发起,是完全中立.全面开放.安全稳定.高性能的操作系统及生态.OpenCloudOS 沉淀了多家厂商在软件和开源生态的优势,继承了腾讯 ...