在上一篇文章中介绍了 Silverlight 中同时选中和移动多个控件的实现方式,但是并没有对控件是否移出边界进行检测,因此可以把控件拖出容器边界外面,这实际应用中当然是不允许的。还有一点就选中的控件只有选中部分会包含在选择区域中,不会把整个控件都自动包含在选择区域中。以下就上面的两个问题的解决方式做一简单介绍。
在上一篇文章中介绍了 Silverlight 中同时选中和移动多个控件的实现方式,但是并没有对控件是否移出边界进行检测,因此可以把控件拖出容器边界外面,这实际应用中当然是不允许的。还有一点就选中的控件只有选中部分会包含在选择区域中,不会把整个控件都自动包含在选择区域中。以下就上面的两个问题的解决方式做一简单介绍。
1、对于第一个问题,只要在移动控件时,对控件移动到的新位置做一个判断就可以,下面是修改后的代码:
/* rect 的 X 轴值和 Y 轴值 */ double rLeft = (double)rect.GetValue(Canvas.LeftProperty); double rTop = (double)rect.GetValue(Canvas.TopProperty); double deltaV = e.GetPosition(rootCanvas).Y - origPoint.Y; double deltaH = e.GetPosition(rootCanvas).X - origPoint.X; double newTop = deltaV + rTop; double newLeft = deltaH + rLeft; if (newTop < 0) // 已经拖出上侧边缘 { newTop = 0; deltaV = 0; } else if (newTop > rootCanvas.ActualHeight - rect.ActualHeight) // 已经拖出下侧边缘 { newTop = rootCanvas.ActualHeight - rect.ActualHeight; deltaV = newTop - rTop; } if (newLeft < 0) // 已经拖出左侧边缘 { newLeft = 0; deltaH = 0; } else if (newLeft > rootCanvas.ActualWidth - rect.ActualWidth) // 已经拖出右侧边缘 { newLeft = rootCanvas.ActualWidth - rect.ActualWidth; deltaH = newLeft - rLeft; } foreach (var se in selectedElements) { double cLeft = deltaH + (double)se.GetValue(Canvas.LeftProperty); double cTop = deltaV + (double)se.GetValue(Canvas.TopProperty); se.SetValue(Canvas.LeftProperty, cLeft); se.SetValue(Canvas.TopProperty, cTop); }
注意对下侧边缘的判断要用容器的高减去 rect(选择区域)的高,对于右侧边缘的判断同样要用容器的宽减去 rect 的宽,这是因为通过e.GetPosition(UIElement).X和e.GetPosition(UIElement).Y取得值是 UIElement 的左侧和顶部距容器左侧和顶部的值。
2、对于第二个问题,如果某个控件被选中,只要将该选择区域扩大把控件所在的矩形区域包含在内即可实现(可以通过Rect的Union方法实现),修改后的代码如下:
Rect finalRect = Rect.Empty; // 最终要显示的选择区域 Rect temp = Rect.Empty; do { if (finalRect != Rect.Empty) temp = new Rect(finalRect.X, finalRect.Y, finalRect.Width, finalRect.Height); foreach (FrameworkElement item in rootCanvas.Children) { if (item as Rectangle != null) continue; double cLeft = (double)item.GetValue(Canvas.LeftProperty); double cTop = (double)item.GetValue(Canvas.TopProperty); Rect rc1 = new Rect(selectedRect.X, selectedRect.Y, selectedRect.Width, selectedRect.Height); Rect rc2 = new Rect(cLeft, cTop, item.ActualWidth, item.ActualHeight); rc1.Intersect(rc2); /* 判断控件所在的矩形区域与选择的矩形区域是否相交 */ if (rc1 != Rect.Empty) { selectedRect.Union(rc2); /* 扩展 selectedRect 时可能会有新控件包含进选择区域,因此用 do while 循环判断 */ finalRect.Union(rc2); if (!selectedElements.Contains(item)) selectedElements.Add(item); } } } while (temp != finalRect); /* 如果 temp == finalRect 说明没有新控件选择进来 */ if (finalRect != Rect.Empty) { /* 重新设置选择区域的大小和位置 */ rect.SetValue(Canvas.TopProperty, finalRect.Y); rect.SetValue(Canvas.LeftProperty, finalRect.X); rect.SetValue(Rectangle.WidthProperty, finalRect.Width); rect.SetValue(Rectangle.HeightProperty, finalRect.Height); }
同时将上面的代码从鼠标的点击事件中移到了鼠标的弹起事件中,这样在鼠标弹起时就可以自动将选中的控件包含在选择区域内。代码见上一篇文章的附件或到http://zdd.me/myfiles 下载。
演示地址 http://v.zdd.me/testpage.html