WPF 截图控件之绘制方框与椭圆(四) 「仿微信」

前言

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

1.WPF实现截屏「仿微信」
2.WPF 实现截屏控件之移动(二)「仿微信」
3.WPF 截图控件之伸缩(三) 「仿微信」

正文

有开发者在B站反馈第三篇有Issues已修复。
WPF 截图控件之绘制方框与椭圆(四) 「仿微信」

实现在截图区域内绘制 方框椭圆 有两种方式
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();        }    } 

完整代码如下

WPF 截图控件之绘制方框与椭圆(四) 「仿微信」

项目地址

  • 框架名:WPFDevelopers
  • 作者:WPFDevelopers
  • GitHub
  • Gitee
发表评论

相关文章