近期公司有个新的定制,先简要说明下:
窗口上有个播放区域,区域上悬浮了很多可视对象(DrawingVisual),全部是动态生成的....
现在的需求是在这些矩形框上需要添加右键快捷菜单...
需求知道了,懂wpf的都知道,DrawingVisual是极其简约的一个视图对象,是没有属性可以绑定鼠标右键菜单,所以我的思路是,在Canvas上绑定快捷菜单,通过鼠标位置判断当前是否在矩形框里面,如果是,则显示对于的菜单,否则就隐藏起来
好了,需求和解决方案整理完成,那么就开始吧!
先看下整体效果:
<Window x:Class="DrawingHelper.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DrawingHelper"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<ResourceDictionary>
<ContextMenu x:Key="right">
<MenuItem Header="默认的" />
<MenuItem Header="单击框" Style="{DynamicResource item}" Click="MenuItem_Click" />
</ContextMenu>
<Style TargetType="MenuItem" x:Key="item">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:MainWindow},Path=IsOverRect}" Value="true">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid x:Name="grid" Margin="10">
<local:CustomCanvas x:Name="canvas"
Background="#7d7d7d"
ContextMenu="{StaticResource right}"
MouseLeftButtonDown="canvas_MouseLeftButtonDown"
MouseMove="canvas_MouseMove"
MouseLeftButtonUp="canvas_MouseLeftButtonUp"/>
</Grid>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Button Content="生成" Click="Button_Click" />
</StackPanel>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace DrawingHelper
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
List<Visual> vsOver = new List<Visual>();
bool ismove = false;
Visual slectedVisual;
Vector vectorDownOffice;
public MainWindow()
{
InitializeComponent();
//注册事件
//EventManager.RegisterClassHandler(typeof(CustomCanvas),
// CustomCanvas.RightContextMenuOpeningEvent,
// new RoutedEventHandler(RightContextMenuOpening), true);
canvas.RightContextMenuOpening += RightContextMenuOpening;
}
/// <summary>
/// 是否悬浮在框上
/// </summary>
public bool IsOverRect
{
get { return (bool)GetValue(IsOverRectProperty); }
set { SetValue(IsOverRectProperty, value); }
}
public static readonly DependencyProperty IsOverRectProperty =
DependencyProperty.Register("IsOverRect", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
/// <summary>
/// 单击生成
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button_Click(object sender, RoutedEventArgs e)
{
Rect rect = new Rect();
rect.Size = new Size(100, 100);
Random r = new Random(DateTime.Now.Millisecond);
var x = r.Next(0, (int)(canvas.ActualWidth - rect.Size.Width));
var y = r.Next(0, (int)(canvas.ActualHeight - rect.Size.Width));
rect.Location = new Point(x, y);
canvas.AddVisual(rect);
}
/// <summary>
/// 单击鼠标悬浮的框时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show($"当前选中:{vsOver.Count}");
}
/// <summary>
/// 左键被按下时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
ismove = true;
var point = e.GetPosition(canvas);
var vs = canvas.GetVisualByPoint(point);
slectedVisual = vs.FirstOrDefault();
if (slectedVisual is DrawingVisual drawing)
{
vectorDownOffice = point - drawing.Drawing.Bounds.Location;
}
}
/// <summary>
/// 移动时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
if (ismove && slectedVisual != null)
{
var point = e.GetPosition(canvas) - vectorDownOffice;
Rect rect = new Rect();
rect.Size = new Size(100, 100);
rect.X = point.X;
rect.Y = point.Y;
canvas.MoveVisual(slectedVisual, rect);
}
}
/// <summary>
/// 左键被抬起时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ismove = false;
slectedVisual = null;
}
/// <summary>
/// 快捷菜单打开之前
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void RightContextMenuOpening(object sender, RoutedEventArgs e)
{
//获取相对面板的位置
var point = Mouse.GetPosition(canvas);
var vs = canvas.GetVisualByPoint(point);
vsOver = new List<Visual>(vs);
IsOverRect = vs.Length > 0;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace DrawingHelper
{
/// <summary>
/// 自定义面板
/// </summary>
class CustomCanvas : Canvas
{
/// <summary>
/// 透明度
/// </summary>
double opacity = 0.8;
public CustomCanvas()
{
ContextMenuOpening += CustomCanvas_ContextMenuOpening;
}
/// <summary>
/// 菜单打开之前
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CustomCanvas_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
//RaiseEvent(new RoutedEventArgs(RightContextMenuOpeningEvent, e));//事件推送
RightContextMenuOpening?.Invoke(this, e);
}
/*
/// <summary>
/// 声明自定义事件
/// </summary>
public static readonly RoutedEvent RightContextMenuOpeningEvent =
EventManager.RegisterRoutedEvent(
"RightContextMenuOpeningEvent",
RoutingStrategy.Direct,
typeof(EventHandler<ContextMenuEventArgs>),
typeof(CustomCanvas));
/// <summary>
/// Raised when the VideoCellContextMenuOpeningEvent changed.
/// </summary>
public event RoutedEventHandler RightContextMenuOpening
{
add { AddHandler(RightContextMenuOpeningEvent, value); }
remove { RemoveHandler(RightContextMenuOpeningEvent, value); }
}
*/
/// <summary>
/// 右键菜单打开之前
/// </summary>
public event EventHandler<ContextMenuEventArgs> RightContextMenuOpening;
/// <summary>
/// 当前所有的图形
/// </summary>
List<Visual> vs = new List<Visual>();
/// <summary>
/// 边框画刷
/// </summary>
Pen pen = new Pen(new SolidColorBrush(Colors.Black), 2);
/// <summary>
/// 添加个图形
/// </summary>
/// <param name="rect"></param>
public void AddVisual(Rect rect)
{
DrawingVisual dv = new DrawingVisual();
using (var drawingContext = dv.RenderOpen())
{
drawingContext.PushOpacity(opacity);
drawingContext.DrawRectangle(null, pen, rect);
}
vs.Add(dv);
this.AddVisualChild(dv);
this.AddLogicalChild(dv);
}
/// <summary>
/// 图形总数
/// </summary>
protected override int VisualChildrenCount => vs.Count;
/// <summary>
///
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
protected override Visual GetVisualChild(int index)
{
return vs[index];
}
/// <summary>
/// 根据坐标返回图形
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
public Visual[] GetVisualByPoint(Point point)
{
List<Visual> vis = new List<Visual>();
vs.ForEach(c =>
{
if (c is DrawingVisual dv)
{
var dr = dv.Drawing;
var x = dr.Bounds.X;
var y = dr.Bounds.Y;
var w = dr.Bounds.Width;
var h = dr.Bounds.Height;
if (point.X >= x && point.X <= x + w && point.Y >= y && point.Y <= y + h)
{
vis.Add(c);
}
}
});
return vis.ToArray();
}
/// <summary>
/// 移动指定的
/// </summary>
/// <param name="visual"></param>
/// <param name="point"></param>
public void MoveVisual(Visual visual, Rect rect)
{
if (visual is DrawingVisual drawing)
{
using (var dc = drawing.RenderOpen())
{
dc.PushOpacity(opacity);
dc.DrawRectangle(null, pen, rect);
}
}
}
}
}
有需要的朋友,也可以移步下载:点击下载