Silverlight 選擇和移動多個控件——移出邊界檢測和自動將選中的控件全部包含在選擇框中

在上一篇文章中介绍了 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


為了你的幸福,我一直在努力!