4

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

 1 year ago
source link: https://www.cnblogs.com/yanjinhua/p/16529311.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

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

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

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

实现在截图区域内绘制 方框椭圆 有两种方式
1)可以在截图的区域内部添加一个Canvas宽高填充至区域内,在进行绘制方框或椭圆。
2)直接在外层的Canvas中添加,这样需要判断鼠标按下的位置和移动的位置必须在已截图区域内,如超出范围也不绘制到区域外。

本章使用了第二种方式
此篇更新截图时隐藏当前窗口

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

新增定义 画方框、椭圆、颜色选择框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;

新增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>

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK