• Canvas上批量创建可视对象(DrawingVisual)管理,获取鼠标悬浮图形状态,并控制鼠标右键快捷菜单等...


    近期公司有个新的定制,先简要说明下:

    窗口上有个播放区域,区域上悬浮了很多可视对象(DrawingVisual),全部是动态生成的....

    现在的需求是在这些矩形框上需要添加右键快捷菜单...

     

    需求知道了,懂wpf的都知道,DrawingVisual是极其简约的一个视图对象,是没有属性可以绑定鼠标右键菜单,所以我的思路是,在Canvas上绑定快捷菜单,通过鼠标位置判断当前是否在矩形框里面,如果是,则显示对于的菜单,否则就隐藏起来

     

    好了,需求和解决方案整理完成,那么就开始吧!

    先看下整体效果:

     1 <Window x:Class="DrawingHelper.MainWindow"
     2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     6         xmlns:local="clr-namespace:DrawingHelper"
     7         mc:Ignorable="d"
     8         Title="MainWindow" Height="450" Width="800">
     9 
    10     <Window.Resources>
    11         <ResourceDictionary>
    12 
    13             <ContextMenu x:Key="right">
    14                 <MenuItem Header="默认的" />
    15                 <MenuItem Header="单击框" Style="{DynamicResource item}" Click="MenuItem_Click" />
    16             </ContextMenu>
    17 
    18             <Style TargetType="MenuItem" x:Key="item">
    19                 <Setter Property="Visibility" Value="Collapsed" />
    20                 <Style.Triggers>
    21                     <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:MainWindow},Path=IsOverRect}" Value="true">
    22                         <Setter Property="Visibility" Value="Visible" />
    23                     </DataTrigger>
    24                 </Style.Triggers>
    25             </Style>
    26             
    27         </ResourceDictionary>
    28     </Window.Resources>
    29     <Grid>
    30         <Grid x:Name="grid" Margin="10">
    31             <local:CustomCanvas x:Name="canvas" 
    32                                 Background="#7d7d7d" 
    33                                 ContextMenu="{StaticResource right}"  
    34                                 MouseLeftButtonDown="canvas_MouseLeftButtonDown"
    35                                 MouseMove="canvas_MouseMove"
    36                                 MouseLeftButtonUp="canvas_MouseLeftButtonUp"/>
    37         </Grid>
    38 
    39         <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
    40             <Button Content="生成" Click="Button_Click" />
    41         </StackPanel>
    42     </Grid>
    43 </Window>
    UI前段代码
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Diagnostics;
      4 using System.Linq;
      5 using System.Text;
      6 using System.Threading.Tasks;
      7 using System.Windows;
      8 using System.Windows.Controls;
      9 using System.Windows.Data;
     10 using System.Windows.Documents;
     11 using System.Windows.Input;
     12 using System.Windows.Media;
     13 using System.Windows.Media.Imaging;
     14 using System.Windows.Navigation;
     15 using System.Windows.Shapes;
     16 
     17 namespace DrawingHelper
     18 {
     19     /// <summary>
     20     /// MainWindow.xaml 的交互逻辑
     21     /// </summary>
     22     public partial class MainWindow : Window
     23     {
     24         List<Visual> vsOver = new List<Visual>();
     25         bool ismove = false;
     26         Visual slectedVisual;
     27         Vector vectorDownOffice;
     28 
     29         public MainWindow()
     30         {
     31             InitializeComponent();
     32 
     33             //注册事件
     34             //EventManager.RegisterClassHandler(typeof(CustomCanvas),
     35             //    CustomCanvas.RightContextMenuOpeningEvent,
     36             //    new RoutedEventHandler(RightContextMenuOpening), true);
     37 
     38             canvas.RightContextMenuOpening += RightContextMenuOpening;
     39         }
     40 
     41         /// <summary>
     42         /// 是否悬浮在框上
     43         /// </summary>
     44         public bool IsOverRect
     45         {
     46             get { return (bool)GetValue(IsOverRectProperty); }
     47             set { SetValue(IsOverRectProperty, value); }
     48         }
     49 
     50         public static readonly DependencyProperty IsOverRectProperty =
     51             DependencyProperty.Register("IsOverRect", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
     52 
     53         /// <summary>
     54         /// 单击生成
     55         /// </summary>
     56         /// <param name="sender"></param>
     57         /// <param name="e"></param>
     58         private void Button_Click(object sender, RoutedEventArgs e)
     59         {
     60             Rect rect = new Rect();
     61             rect.Size = new Size(100, 100);
     62 
     63             Random r = new Random(DateTime.Now.Millisecond);
     64             var x = r.Next(0, (int)(canvas.ActualWidth - rect.Size.Width));
     65             var y = r.Next(0, (int)(canvas.ActualHeight - rect.Size.Width));
     66 
     67             rect.Location = new Point(x, y);
     68 
     69             canvas.AddVisual(rect);
     70         }
     71 
     72         /// <summary>
     73         /// 单击鼠标悬浮的框时
     74         /// </summary>
     75         /// <param name="sender"></param>
     76         /// <param name="e"></param>
     77         private void MenuItem_Click(object sender, RoutedEventArgs e)
     78         {
     79             MessageBox.Show($"当前选中:{vsOver.Count}");
     80         }
     81 
     82         /// <summary>
     83         /// 左键被按下时
     84         /// </summary>
     85         /// <param name="sender"></param>
     86         /// <param name="e"></param>
     87         private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
     88         {
     89             ismove = true;
     90             var point = e.GetPosition(canvas);
     91 
     92             var vs = canvas.GetVisualByPoint(point);
     93             slectedVisual = vs.FirstOrDefault();
     94 
     95             if (slectedVisual is DrawingVisual drawing)
     96             {
     97                 vectorDownOffice = point - drawing.Drawing.Bounds.Location;
     98             }
     99         }
    100 
    101         /// <summary>
    102         /// 移动时
    103         /// </summary>
    104         /// <param name="sender"></param>
    105         /// <param name="e"></param>
    106         private void canvas_MouseMove(object sender, MouseEventArgs e)
    107         {
    108             if (ismove && slectedVisual != null)
    109             {
    110                 var point = e.GetPosition(canvas) - vectorDownOffice;
    111 
    112                 Rect rect = new Rect();
    113                 rect.Size = new Size(100, 100);
    114                 rect.X = point.X;
    115                 rect.Y = point.Y;
    116 
    117                 canvas.MoveVisual(slectedVisual, rect);
    118             }
    119         }
    120 
    121         /// <summary>
    122         /// 左键被抬起时
    123         /// </summary>
    124         /// <param name="sender"></param>
    125         /// <param name="e"></param>
    126         private void canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    127         {
    128             ismove = false;
    129             slectedVisual = null;
    130         }
    131 
    132         /// <summary>
    133         /// 快捷菜单打开之前
    134         /// </summary>
    135         /// <param name="sender"></param>
    136         /// <param name="e"></param>
    137         void RightContextMenuOpening(object sender, RoutedEventArgs e)
    138         {
    139             //获取相对面板的位置
    140             var point = Mouse.GetPosition(canvas);
    141 
    142             var vs = canvas.GetVisualByPoint(point);
    143             vsOver = new List<Visual>(vs);
    144 
    145             IsOverRect = vs.Length > 0;
    146         }
    147     }
    148 
    149 }
    UI后端代码
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 using System.Windows;
      7 using System.Windows.Controls;
      8 using System.Windows.Media;
      9 
     10 namespace DrawingHelper
     11 {
     12     /// <summary>
     13     /// 自定义面板
     14     /// </summary>
     15     class CustomCanvas : Canvas
     16     {
     17         /// <summary>
     18         /// 透明度
     19         /// </summary>
     20         double opacity = 0.8;
     21 
     22         public CustomCanvas()
     23         {
     24             ContextMenuOpening += CustomCanvas_ContextMenuOpening;
     25         }
     26 
     27         /// <summary>
     28         /// 菜单打开之前
     29         /// </summary>
     30         /// <param name="sender"></param>
     31         /// <param name="e"></param>
     32         private void CustomCanvas_ContextMenuOpening(object sender, ContextMenuEventArgs e)
     33         {
     34             //RaiseEvent(new RoutedEventArgs(RightContextMenuOpeningEvent, e));//事件推送
     35 
     36             RightContextMenuOpening?.Invoke(this, e);
     37         }
     38 
     39         /*
     40         /// <summary>
     41         /// 声明自定义事件
     42         /// </summary>
     43         public static readonly RoutedEvent RightContextMenuOpeningEvent =
     44             EventManager.RegisterRoutedEvent(
     45                             "RightContextMenuOpeningEvent",
     46                             RoutingStrategy.Direct,
     47                             typeof(EventHandler<ContextMenuEventArgs>),
     48                             typeof(CustomCanvas));
     49 
     50         /// <summary>
     51         /// Raised when the VideoCellContextMenuOpeningEvent changed.
     52         /// </summary>
     53         public event RoutedEventHandler RightContextMenuOpening
     54         {
     55             add { AddHandler(RightContextMenuOpeningEvent, value); }
     56             remove { RemoveHandler(RightContextMenuOpeningEvent, value); }
     57         }
     58         */
     59 
     60         /// <summary>
     61         /// 右键菜单打开之前
     62         /// </summary>
     63         public event EventHandler<ContextMenuEventArgs> RightContextMenuOpening;
     64 
     65         /// <summary>
     66         /// 当前所有的图形
     67         /// </summary>
     68         List<Visual> vs = new List<Visual>();
     69 
     70         /// <summary>
     71         /// 边框画刷
     72         /// </summary>
     73         Pen pen = new Pen(new SolidColorBrush(Colors.Black), 2);
     74 
     75         /// <summary>
     76         /// 添加个图形
     77         /// </summary>
     78         /// <param name="rect"></param>
     79         public void AddVisual(Rect rect)
     80         {
     81             DrawingVisual dv = new DrawingVisual();
     82 
     83             using (var drawingContext = dv.RenderOpen())
     84             {
     85                 drawingContext.PushOpacity(opacity);
     86                 drawingContext.DrawRectangle(null, pen, rect);
     87             }
     88 
     89             vs.Add(dv);
     90 
     91             this.AddVisualChild(dv);
     92             this.AddLogicalChild(dv);
     93         }
     94 
     95         /// <summary>
     96         /// 图形总数
     97         /// </summary>
     98         protected override int VisualChildrenCount => vs.Count;
     99 
    100         /// <summary>
    101         /// 
    102         /// </summary>
    103         /// <param name="index"></param>
    104         /// <returns></returns>
    105         protected override Visual GetVisualChild(int index)
    106         {
    107             return vs[index];
    108         }
    109 
    110         /// <summary>
    111         /// 根据坐标返回图形
    112         /// </summary>
    113         /// <param name="point"></param>
    114         /// <returns></returns>
    115         public Visual[] GetVisualByPoint(Point point)
    116         {
    117             List<Visual> vis = new List<Visual>();
    118             vs.ForEach(c =>
    119             {
    120                 if (c is DrawingVisual dv)
    121                 {
    122                     var dr = dv.Drawing;
    123 
    124                     var x = dr.Bounds.X;
    125                     var y = dr.Bounds.Y;
    126                     var w = dr.Bounds.Width;
    127                     var h = dr.Bounds.Height;
    128 
    129                     if (point.X >= x && point.X <= x + w && point.Y >= y && point.Y <= y + h)
    130                     {
    131                         vis.Add(c);
    132                     }
    133                 }
    134             });
    135             return vis.ToArray();
    136         }
    137 
    138         /// <summary>
    139         /// 移动指定的
    140         /// </summary>
    141         /// <param name="visual"></param>
    142         /// <param name="point"></param>
    143         public void MoveVisual(Visual visual, Rect rect)
    144         {
    145             if (visual is DrawingVisual drawing)
    146             {
    147                 using (var dc = drawing.RenderOpen())
    148                 {
    149                     dc.PushOpacity(opacity);
    150                     dc.DrawRectangle(null, pen, rect);
    151                 }
    152             }
    153         }
    154     }
    155 }
    CustomCanvas 扩展类

    有需要的朋友,也可以移步下载:点击下载

  • 相关阅读:
    .NetCore中获取持久化哈希值
    switch类型模式
    .NET6之MiniAPI(三):Response
    .NET6之MiniAPI(二):request
    .NET6之MiniAPI(一):开始Mini API
    .net6给winform带来的新功能
    2021.NET Conf China上的GraphQL
    Maptalks 注册自定义绘图模块
    MinIO服务器搭建(单机版)
    C++ mysqlclient create and insert into tables
  • 原文地址:https://www.cnblogs.com/xuling-297769461/p/12523103.html
Copyright © 2020-2023  润新知