选择后比如可以将子控件的Border设置为红色边框
说下这个功能的大致原理。背景是一个Grid,比如里面放了很多的Button. 同时还有一个红色边框的RectAngele来显示框框。
RectAngele默认不显示。
鼠标左键按下时,记录当时鼠标位置作为RectAngele的左上角起点,
鼠标按住移动时,记录当时的鼠标位置作为RectAngele的右下角终点。
这样两点,就确定了RectAngele的位置,鼠标按住不停移动,这个RectAngele就会不停的变化大小。
用到了几个事件
PreviewMouseMove,PreviewMouseLeftButtonDown,PreviewMouseLeftButtonUp。
这样的功能,当然可以在业务层做 定义Grid Button RectRange 的界面XAML中做.。如果有多个界面要做框选功能,岂不是代码要复制来复制去复制几遍?
!这样太LOW,不能忍,必须抽象到控件层次,与业务逻辑无关。
新增控件 GridRect 继承 Grid,把框选功能集成到控件里。 这里有一个关键的地方,Grid有可能被分为很多Row 和Clomn。不同的Button放在不同的行列里。
但是这个RectRange 的位置其实是和行列无关的。它不能固定在某个行列里。所以RectRange要特殊处理。
废话不多说,直接上源码,拿去用吧!
public class GridRect : Grid
{
private Rectangle rect;
private Grid rectgrid;//因为可能被分为很多列和行,而rect的父容器不能被分组
public GridRect()
{
Background = Brushes.Transparent;
this.Loaded += GridRect_Loaded;
}
public delegate void delegateSelectChildChange(List SelectedControls);
public delegateSelectChildChange SelectChildChange { get; set; }
private void GridRect_Loaded(object sender, RoutedEventArgs e)
{
rectgrid = new Grid();
rect = new Rectangle()
{
IsHitTestVisible = false,
StrokeThickness = 1,
Fill = Brushes.Transparent,
Visibility = System.Windows.Visibility.Collapsed,
Stroke = Brushes.Red,
HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
VerticalAlignment = System.Windows.VerticalAlignment.Top
};
//因为可能被分为很多列和行,而rect的父容器不能被分组
Grid.SetRowSpan(rectgrid, 100);
Grid.SetColumnSpan(rectgrid, 100);
rectgrid.Children.Add(rect);
this.Children.Add(rectgrid);
Panel.SetZIndex(rectgrid, 999);
}
#region 框选功能
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
var StartPoint = e.GetPosition(this);
RectStartPoint.X = Math.Truncate(StartPoint.X);
RectStartPoint.Y = Math.Truncate(StartPoint.Y);
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Key == Key.Escape && rect.Visibility == Visibility.Visible)
{
rect.Visibility = Visibility.Collapsed;
}
}
private Point RectStartPoint = new Point();
private Point RectEndPoint = new Point();
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed)
{
//该事件在界面加载完后会马上出发,因为鼠标相对于grid的位置会更新,且Pressed,此时红框不该显示
if (rect.Visibility != Visibility.Visible
&& RectStartPoint.X + RectStartPoint.Y !=0)
{
rect.Visibility = Visibility.Visible;
}
Point p = e.GetPosition(this);
double width = Math.Truncate(Math.Abs(p.X - RectStartPoint.X));
double height = Math.Truncate(Math.Abs(p.Y - RectStartPoint.Y));
rect.Margin = new Thickness(RectStartPoint.X, RectStartPoint.Y, 0, 0);
rect.Height = height;
rect.Width = width;
RectEndPoint.X = RectStartPoint.X + width;
RectEndPoint.Y = RectStartPoint.Y + height;
}
}
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (rect.Visibility == Visibility.Visible)
{
List SelectedControlsTmp=new List();
foreach (FrameworkElement item in this.Children)
{
if (item == rect || item ==rectgrid)
{
continue;
}
GeneralTransform generalTransform1 = item.TransformToVisual(this);
Point lefttop = generalTransform1.Transform(new Point(0, 0));
Point rightbuttom = new Point(lefttop.X + item.ActualWidth, lefttop.Y + item.ActualHeight);
Point btnrighttop = new Point(rightbuttom.X, lefttop.Y);
Point btnleftbuttom = new Point(lefttop.X, rightbuttom.Y);
Rect rectTmp = new Rect(lefttop, rightbuttom);
Rect rectRed = new Rect(RectStartPoint, RectEndPoint);
if (rectTmp.IntersectsWith(rectRed))
{
SelectedControlsTmp.Add(item);
}
}
SelectChildChange?.Invoke(SelectedControlsTmp);
}
}
#endregion
}
拓展:可以做成模板类,比较灵活,我想了下使用GridRect
public class GridRect: GridRect where T:FrameworkElement
{
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (rect.Visibility == Visibility.Visible)
{
List lstbtn = new List();
FindLogicTree(this, lstbtn);
foreach (FrameworkElement item in lstbtn)
{
if (item == rect || item == rectgrid || item.Visibility != Visibility.Visible)
{
continue;
}
GeneralTransform generalTransform1 = item.TransformToVisual(this);
//按钮的坐标框
Point lefttop = generalTransform1.Transform(new Point(0, 0));
Point rightbuttom = new Point(lefttop.X + item.ActualWidth, lefttop.Y + item.ActualHeight);
//选择框的坐标
Point btnrighttop = new Point(rect.Margin.Left, rect.Margin.Top);
Point btnleftbuttom = new Point(rect.Margin.Left + rect.Width, rect.Margin.Top + rect.Height);
Rect rectTmp = new Rect(lefttop, rightbuttom);
Rect rectRed = new Rect(btnrighttop, btnleftbuttom);
if (rectTmp.IntersectsWith(rectRed))
{
SelectedControlsTmp.Add(item);
}
}
SelectChildChange?.Invoke(SelectedControlsTmp);
}
}
}