在去年年底,为了学习Silverlight4.0的新特性,我萌生了开发一个基于其新特性的项目。当然在这个项目中使用了包括鼠标右键菜单(Popup),打印功能(PrintDocument),导航功能,摄像头,图片上传等。当然目前这个产品已在我们的官方产品Discuz!NT3.1中使用,今天开源的仅是本应用的源码。
下面链接中是产品的运行截图:
http://www.cnblogs.com/daizhj/archive/2010/02/26/1674389.html
好了,接下来介绍一下产品的源码分布:
其中:
ChildWindows\
CWMessageBox.xaml:显示窗口信息控件,用于显示系统提示的各种消息
CWViewUploadedImage.xaml:显示用于上传头像或文件之后的显示结果(包括大中小三种尺寸)
Controls\
FocusRectangle.xaml: 焦点选择区域控件及相应用户拖动效果
ImageButton.xaml:图片控件
InkMenu.xaml:ink涂鸦工具栏控件
Cursors\
CustomCursors.xaml: 定制鼠标图标控件, 用于当鼠标进入FocusRectangle区域后显示定制的十字箭头
Shader\三个silverlight滤镜
Images\ 项目中使用的图标
Utils\相关工具类
Constants.cs,Converter.cs,UserFile.cs,FileCollection.cs, FileUploader.cs 图片上传代码
Utils.cs 常用函数封装工具类
AdvanceMode.xaml:高级模式的编辑窗口
ImageBrowser.xaml:图片浏览和编辑上传窗口
NavPage.xaml:导航窗口
WebCam.xaml:摄像头功能和上传窗口
好的,产品布局就介绍到这里了,下面是对于之前朋友感兴趣的一些功能的代码介绍。
首先就是焦点选择框(矩形)的实现原理和相应代码,位于FocusRectangle.xaml和FocusRectangle.xaml.cs 原理就是首先绘制8个小矩形,作为用户进行鼠标操作的入口(均定制了鼠标点击操作代码),然后将这8个小矩形分布在一个大矩形的四角和两两节点间的中心位置,当然也加入鼠标的拖动和“上下左右扩展”代码,明确了实现方式之后,就看一下源码来加深一下理解了:
XAML:
<Canvas Name="ViewportHost" Height="270" Width="270" Background="Gray">
<ScrollViewer Canvas.ZIndex="0" Name="imageScroll" BorderThickness="0" Background="Transparent" Width="270" Height="270" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
<Rectangle Name="Viewport" Width="270" Height="270" Canvas.ZIndex="100">
<Rectangle.Fill>
<ImageBrush>
<ImageBrush.ImageSource>
<BitmapImage x:Name="selectedImage" UriSource ="../Images/main.jpg"/>
</ImageBrush.ImageSource>
</ImageBrush>
</Rectangle.Fill>
</Rectangle>
</ScrollViewer>
<!--<TextBlock x:Name="msgBox" Width="269" Text="000" Foreground="Red" Height="100" Canvas.ZIndex="10000" />-->
<local:CustomCursors x:Name="customCursors" Visibility="Collapsed"></local:CustomCursors>
<Rectangle Name="FocusRect" Canvas.Left="5" Canvas.Top="5" Fill="Transparent" Opacity="1" Stroke="White" StrokeThickness="1" />
</Canvas>
</Canvas>
XAML文件中包括一个ScrollViewer用于实现图片的缩放效果,CustomCursors用于鼠标移入焦点区域时显示焦点图标而不是鼠标沙漏。
下面则是FocusRectangle.xaml.cs代码,包括8个小矩形的枚举标识:
/// <summary>
/// 方形中八个点的相对位置
/// </summary>
enum HitDownSquare
{
HDS_NONE = 0,
/// <summary>
/// 顶
/// </summary>
HDS_TOP = 1,
/// <summary>
/// 右
/// </summary>
HDS_RIGHT = 2,
/// <summary>
/// 底
/// </summary>
HDS_BOTTOM = 3,
/// <summary>
/// 左
/// </summary>
HDS_LEFT = 4,
/// <summary>
/// 左上
/// </summary>
HDS_TOPLEFT = 5,
/// <summary>
/// 右上
/// </summary>
HDS_TOPRIGHT = 6,
/// <summary>
/// 左下
/// </summary>
HDS_BOTTOMLEFT = 7,
/// <summary>
/// 右下
/// </summary>
HDS_BOTTOMRIGHT = 8
}
#endregion
主要的控件类实体,实现各种相关鼠标操作事件和图形绘制事件代码(详见注释):
{
#region 属性设置
/// <summary>
/// 8个允许调整控件大小的小正方形
/// </summary>
Rectangle[] SmallRect = new Rectangle[8];
/// <summary>
/// 8个小正方形的大小
/// </summary>
Size Square = new Size(6, 6);
/// <summary>
/// 上一次鼠标点击的位置
/// </summary>
Point prevLeftClick;
/// <summary>
/// 8个小正方形的填充色
/// </summary>
Color color = Colors.White;
/// <summary>
/// 标识鼠标左键已被按下并且已开始移动
/// </summary>
bool trackingMouseMove = false;
/// <summary>
/// 当前鼠标点击位置信息
/// </summary>
HitDownSquare CurrHitPlace = new HitDownSquare();
#endregion
public FocusRectangle()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(FocusRectangle_Loaded);
}
#region 初始化相应元素信息
/// <summary>
/// 初始化相应元素信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void FocusRectangle_Loaded(object sender, RoutedEventArgs e)
{
Viewport.MinHeight = Viewport.MinWidth = 16;
Viewport.SetValue(Canvas.TopProperty, (double)ViewportHost.GetValue(Canvas.TopProperty) + (ViewportHost.Height - Viewport.Height) / 2);
Viewport.SetValue(Canvas.LeftProperty, (double)ViewportHost.GetValue(Canvas.LeftProperty) + (ViewportHost.Width - Viewport.Width) / 2);
//初始设置FocusRect
FocusRect.Width = FocusRect.Height = 100;
FocusRect.MaxWidth = ViewportHost.Width;
FocusRect.MaxHeight = ViewportHost.Height;
FocusRect.MinHeight = FocusRect.MinWidth = 8;
FocusRect.SetValue(Canvas.TopProperty, (double)ViewportHost.GetValue(Canvas.TopProperty) + (ViewportHost.Height - FocusRect.Height) / 2);
FocusRect.SetValue(Canvas.LeftProperty, (double)ViewportHost.GetValue(Canvas.LeftProperty) + (ViewportHost.Width - FocusRect.Width) / 2);
#region 8个小正方形位置
//左上
SmallRect[0] = new Rectangle() { Name = "SmallRect0", Width = Square.Width, Height = Square.Height, Fill = new SolidColorBrush(color) };
//上中间
SmallRect[4] = new Rectangle() { Name = "SmallRect4", Width = Square.Width, Height = Square.Height, Fill = new SolidColorBrush(color) };
//右上
SmallRect[1] = new Rectangle() { Name = "SmallRect1", Width = Square.Width, Height = Square.Height, Fill = new SolidColorBrush(color) };
//左下
SmallRect[2] = new Rectangle() { Name = "SmallRect2", Width = Square.Width, Height = Square.Height, Fill = new SolidColorBrush(color) };
//下中间
SmallRect[5] = new Rectangle() { Name = "SmallRect5", Width = Square.Width, Height = Square.Height, Fill = new SolidColorBrush(color) };
//右下
SmallRect[3] = new Rectangle() { Name = "SmallRect3", Width = Square.Width, Height = Square.Height, Fill = new SolidColorBrush(color) };
//左中间
SmallRect[6] = new Rectangle() { Name = "SmallRect6", Width = Square.Width, Height = Square.Height, Fill = new SolidColorBrush(color) };
//右中间
SmallRect[7] = new Rectangle() { Name = "SmallRect7", Width = Square.Width, Height = Square.Height, Fill = new SolidColorBrush(color) };
SetRectangles();
#endregion
#region 事件绑定
foreach (Rectangle smallRectangle in SmallRect)
{
smallRectangle.Fill = new SolidColorBrush(color);
smallRectangle.MouseMove += new MouseEventHandler(smallRectangle_MouseMove);
smallRectangle.MouseLeftButtonUp += new MouseButtonEventHandler(smallRectangle_MouseLeftButtonUp);
smallRectangle.MouseLeftButtonDown += new MouseButtonEventHandler(smallRectangle_MouseLeftButtonDown);
smallRectangle.MouseEnter += new MouseEventHandler(smallRectangle_MouseEnter);
LayoutRoot.Children.Add(smallRectangle);
}
FocusRect.MouseMove += new MouseEventHandler(FocusRect_MouseMove);
FocusRect.MouseLeftButtonDown += new MouseButtonEventHandler(FocusRect_MouseLeftButtonDown);
FocusRect.MouseLeftButtonUp += new MouseButtonEventHandler(FocusRect_MouseLeftButtonUp);
FocusRect.MouseEnter += new MouseEventHandler(FocusRect_MouseEnter);
FocusRect.MouseLeave += new MouseEventHandler(FocusRect_MouseLeave);
#endregion
}
#endregion
#region FocusRect鼠标事件
void FocusRect_MouseLeave(object sender, MouseEventArgs e)
{
customCursors.Visibility = System.Windows.Visibility.Collapsed;
}
void FocusRect_MouseEnter(object sender, MouseEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
element.Cursor = Cursors.None;
customCursors.Visibility = System.Windows.Visibility.Visible;
customCursors.SetPostion(e.GetPosition(LayoutRoot));
}
void FocusRect_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
trackingMouseMove = false;
element.ReleaseMouseCapture();
prevLeftClick.X = prevLeftClick.Y = 0;
element.Cursor = Cursors.None;
if (Viewport.Width < FocusRect.Width)
FocusRect.Width = Viewport.Width;
if (Viewport.Height < FocusRect.Height)
FocusRect.Height = Viewport.Height;
AssureFocusRectMoveInZone(element.Name);
SetRectangles();
}
void FocusRect_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
prevLeftClick = e.GetPosition(element);
trackingMouseMove = true;
if (null != element)
{
element.CaptureMouse();
element.Cursor = Cursors.None;
}
}
/// <summary>
/// 计算并设置Scroll的偏移量
/// </summary>
/// <param name="offSetX">鼠标X轴移动的偏移量</param>
/// <param name="offSetY">鼠标Y轴移动的偏移量</param>
void ComputeScrollOffSet(double offSetX, double offSetY)
{
double FocusRectTop = (double)FocusRect.GetValue(Canvas.TopProperty);
double FocusRectLeft = (double)FocusRect.GetValue(Canvas.LeftProperty);
double ViewportHostTop = (double)ViewportHost.GetValue(Canvas.TopProperty);
double ViewportHostLeft = (double)ViewportHost.GetValue(Canvas.LeftProperty);
//msgBox.Text = "FocusRect.Height" + FocusRect.Height + " ViewportHost.Height" + ViewportHost.Height;
if (offSetY > 0 && (FocusRect.Height + 8) < ViewportHost.Height && (ViewportHostTop + ViewportHost.Height) > (FocusRectTop + FocusRect.Height)) //鼠标向下且未出ViewportHost区域时
imageScroll.ScrollToVerticalOffset(imageScroll.VerticalOffset + (offSetY / 2) * (Viewport.Height / (ViewportHost.Height - FocusRectTop - FocusRect.Height)));
if (offSetY < 0 && (FocusRect.Height + 8) < ViewportHost.Height && ViewportHostTop < FocusRectTop) //鼠标向上且未出ViewportHost区域时
imageScroll.ScrollToVerticalOffset(imageScroll.VerticalOffset + (offSetY / 2) * ((Viewport.Height / FocusRectTop)));
if (offSetX > 0 && (FocusRect.Width + 8) < ViewportHost.Width && (ViewportHostLeft + ViewportHost.Width) > (FocusRectLeft + FocusRect.Width)) //鼠标向右且未出ViewportHost区域时
imageScroll.ScrollToHorizontalOffset(imageScroll.HorizontalOffset + (offSetX /2) * (Viewport.Width / (ViewportHost.Width - FocusRectLeft - FocusRect.Width)));
if (offSetX < 0 && (FocusRect.Width + 8) < ViewportHost.Width && ViewportHostLeft < FocusRectLeft) //鼠标向左且未出ViewportHost区域时
imageScroll.ScrollToHorizontalOffset(imageScroll.HorizontalOffset + (offSetX/2) * ((Viewport.Width / FocusRectLeft)));
//msgBox.Text = imageScroll.HorizontalOffset.ToString();
}
/// <summary>
/// FocusRect鼠标移动事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void FocusRect_MouseMove(object sender, MouseEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
if (element != null)
element.Cursor = Cursors.None;
if (trackingMouseMove)
{
double offSetX = e.GetPosition(element).X - prevLeftClick.X;
double offSetY = e.GetPosition(element).Y - prevLeftClick.Y;
if (((double)element.GetValue(Canvas.TopProperty) + offSetY) >=4 && (((double)FocusRect.GetValue(Canvas.TopProperty) + FocusRect.Height) + offSetY + 3) <= ViewportHost.Height)
element.SetValue(Canvas.TopProperty, (double)element.GetValue(Canvas.TopProperty) + offSetY);
if (((double)element.GetValue(Canvas.LeftProperty) + offSetX) >=4 && (((double)FocusRect.GetValue(Canvas.LeftProperty) + FocusRect.Width) + offSetX + 3) <= ViewportHost.Width)
element.SetValue(Canvas.LeftProperty, (double)element.GetValue(Canvas.LeftProperty) + offSetX);
ComputeScrollOffSet(offSetX, offSetY);
SetRectangles();
}
customCursors.SetPostion(e.GetPosition(LayoutRoot));
}
#endregion
#region 确保FocusRect在Viewport中进行移动和缩放
/// <summary>
/// 确保FocusRect在Viewport中进行缩放
/// </summary>
public void AssureFocusRectZoomInZone(double zoom, double mininum)
{
double ViewPortTop = (double)Viewport.GetValue(Canvas.TopProperty);
double ViewPortLeft = (double)Viewport.GetValue(Canvas.LeftProperty);
double FocusRectTop = (double)FocusRect.GetValue(Canvas.TopProperty);
double FocusRectLeft = (double)FocusRect.GetValue(Canvas.LeftProperty);
if (zoom == mininum)
{
FocusRect.SetValue(Canvas.LeftProperty, ViewPortLeft);
FocusRect.Width = Viewport.Width;
}
else
{
//确保顶部不越界
if (ViewPortTop > FocusRectTop)
FocusRect.SetValue(Canvas.TopProperty, ViewPortTop);
//确保左侧不越界
if (ViewPortLeft > FocusRectLeft)
FocusRect.SetValue(Canvas.LeftProperty, ViewPortLeft);
//判断x是否右侧越界
if ((Viewport.Width + ViewPortLeft) < (FocusRect.Width + FocusRectLeft))
{
//如果已越界,但左侧未越界
if (Viewport.Width > FocusRect.Width)
FocusRect.SetValue(Canvas.LeftProperty, ViewPortLeft + Viewport.Width - FocusRect.Width);
else
FocusRect.Width = Viewport.Width;
}
//判断是否底部越界
if ((Viewport.Height + ViewPortTop) < (FocusRect.Height + FocusRectTop))
{
//如果已越界,但顶部未越界
if (Viewport.Height > FocusRect.Height)
FocusRect.SetValue(Canvas.TopProperty, ViewPortTop + Viewport.Height - FocusRect.Height);
else
FocusRect.Height = Viewport.Height;
}
}
SetRectangles();
}
/// <summary>
/// FocusRect是否在Viewport中,如不在,则确保其不超出Viewport区域
/// </summary>
/// <returns></returns>
bool AssureFocusRectMoveInZone(string elementName)
{
bool result = true;
//try
//{
double ViewPortTop = (double)Viewport.GetValue(Canvas.TopProperty);
double ViewPortLeft = (double)Viewport.GetValue(Canvas.LeftProperty);
double FocusRectTop = (double)FocusRect.GetValue(Canvas.TopProperty);
double FocusRectLeft = (double)FocusRect.GetValue(Canvas.LeftProperty);
if (Viewport.Height > ViewportHost.Height)//已使用放大功能,向上拖动
{
if (0 > FocusRectTop)
{
FocusRect.SetValue(Canvas.TopProperty, (double)ViewportHost.GetValue(Canvas.TopProperty) + 4);
result = false;
}
}
else
{
if (ViewPortTop > FocusRectTop)
{
FocusRect.SetValue(Canvas.TopProperty, ViewPortTop);
result = false;
}
}
if (Viewport.Width >= ViewportHost.Width)//已使用放大功能,向左拖动
{
if (0 > FocusRectLeft)
{
FocusRect.SetValue(Canvas.LeftProperty, (double)ViewportHost.GetValue(Canvas.LeftProperty) + 4);
result = false;
}
}
else
{
if (ViewPortLeft > FocusRectLeft)
{
FocusRect.SetValue(Canvas.LeftProperty, ViewPortLeft);
result = false;
}
}
if (Viewport.Width >= ViewportHost.Width)//已使用放大功能,向右拖动
{
if ((ViewportHost.Width) < (FocusRect.Width + FocusRectLeft))
{
if (elementName == "FocusRect")
FocusRect.SetValue(Canvas.LeftProperty, ViewportHost.Width - FocusRect.Width - 4);
else
{
FocusRect.Width = ViewportHost.Width - FocusRectLeft - 4;
}
result = false;
}
}
else
{
if ((Viewport.Width + ViewPortLeft) < (FocusRect.Width + FocusRectLeft))
{
if (elementName == "FocusRect")
FocusRect.SetValue(Canvas.LeftProperty, ViewPortLeft + Viewport.Width - FocusRect.Width);
else
FocusRect.Width = ViewPortLeft + Viewport.Width - FocusRectLeft;
result = false;
}
}
if (Viewport.Height > ViewportHost.Height)//已使用放大功能,向下拖动
{
if ((ViewportHost.Height) < (FocusRect.Height + FocusRectTop))
{
if (elementName == "FocusRect")
FocusRect.SetValue(Canvas.TopProperty, ViewportHost.Height - FocusRect.Height - 4);
else
FocusRect.Height = ViewportHost.Height - FocusRectTop - 4;
result = false;
}
}
else
{
if ((Viewport.Height + ViewPortTop) < (FocusRect.Height + FocusRectTop))
{
if (elementName == "FocusRect")
FocusRect.SetValue(Canvas.TopProperty, ViewPortTop + Viewport.Height - FocusRect.Height);
else
FocusRect.Height = ViewPortTop + Viewport.Height - FocusRectTop;
result = false;
}
}
//}
//catch
//{
// result = false;
//}
return result;
}
#endregion
#region smallRectangle 鼠标事件
void smallRectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
trackingMouseMove = false;
element.ReleaseMouseCapture();
prevLeftClick.X = prevLeftClick.Y = 0;
element.Cursor = null;
if (Viewport.Width < FocusRect.Width)
FocusRect.Width = Viewport.Width;
if (Viewport.Height < FocusRect.Height)
FocusRect.Height = Viewport.Height;
AssureFocusRectMoveInZone(element.Name);
SetRectangles();
}
/// <summary>
/// 鼠标按下事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void smallRectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
prevLeftClick = e.GetPosition(element);
trackingMouseMove = true;
if (null != element)
{
element.CaptureMouse();
element.Cursor = Cursors.Hand;
}
}
/// <summary>
/// SmallRect[]鼠标移动事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void smallRectangle_MouseMove(object sender, MouseEventArgs e)
{
if (trackingMouseMove)
{
FrameworkElement element = sender as FrameworkElement;
double offSetY = e.GetPosition(element).Y - prevLeftClick.Y;
double offSetX = e.GetPosition(element).X - prevLeftClick.X;
if (AssureFocusRectMoveInZone(element.Name))
{
switch (this.CurrHitPlace)
{
case HitDownSquare.HDS_TOP:
if ((FocusRect.Height - offSetY) > 4)
{
FocusRect.Height = FocusRect.Height - offSetY;
if (FocusRect.Height > 4)
FocusRect.SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) + offSetY);
}
break;
case HitDownSquare.HDS_TOPLEFT:
if ((FocusRect.Height - offSetY) > 4)
{
FocusRect.Height = FocusRect.Height - offSetY;
if (FocusRect.Height > 4)
FocusRect.SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) + offSetY);
}
if ((FocusRect.Width - offSetX) > 4)
{
FocusRect.Width = FocusRect.Width - offSetX;
if (FocusRect.Width > 4)
FocusRect.SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) + offSetX);
}
break;
case HitDownSquare.HDS_TOPRIGHT:
if ((FocusRect.Height - offSetY) >4)
{
FocusRect.Height = FocusRect.Height - offSetY;
if (FocusRect.Height > 4)
FocusRect.SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) + offSetY);
}
if ((FocusRect.Width + offSetX) > 4)
FocusRect.Width = FocusRect.Width + offSetX;
break;
case HitDownSquare.HDS_RIGHT:
if ((FocusRect.Width + offSetX) > 4)
FocusRect.Width = FocusRect.Width + offSetX;
break;
case HitDownSquare.HDS_BOTTOM:
if ((FocusRect.Height + offSetY) > 4)
FocusRect.Height = FocusRect.Height + offSetY;
break;
case HitDownSquare.HDS_BOTTOMLEFT:
if ((FocusRect.Height + offSetY) > 4)
FocusRect.Height = FocusRect.Height + offSetY;
if ((FocusRect.Width - offSetX) > 4)
{
FocusRect.Width = FocusRect.Width - offSetX;
if (FocusRect.Width > 4)
FocusRect.SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) + offSetX);
}
break;
case HitDownSquare.HDS_BOTTOMRIGHT:
if ((FocusRect.Height + offSetY) > 4)
FocusRect.Height = FocusRect.Height + offSetY;
if ((FocusRect.Width + offSetX) >4)
FocusRect.Width = FocusRect.Width + offSetX;
break;
case HitDownSquare.HDS_LEFT:
if ((FocusRect.Width - offSetX) > 4)
{
FocusRect.Width = FocusRect.Width - offSetX;
if (FocusRect.Width > 4)
FocusRect.SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) + offSetX);
}
break;
case HitDownSquare.HDS_NONE:
FocusRect.SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) + offSetX);
FocusRect.SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) + offSetY);
break;
}
}
SetRectangles();
}
}
#endregion
#region 设置8个小正方形位置
/// <summary>
/// 设置8个小正方形位置
/// </summary>
public void SetRectangles()
{
//msgBox.Text = "FocusRect height: " + FocusRect.Height + " Width:" + FocusRect.Width + " Top:" + FocusRect.GetValue(Canvas.TopProperty) + " Left:" + FocusRect.GetValue(Canvas.LeftProperty);
//左上
SmallRect[0].SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) - Square.Width / 2);
SmallRect[0].SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) - Square.Height / 2);
//上中间
SmallRect[4].SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) + (FocusRect.Width - Square.Width)/2);
SmallRect[4].SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) - Square.Height/2);
//右上
SmallRect[1].SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) + FocusRect.Width - Square.Width/2);
SmallRect[1].SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) - Square.Height / 2);
//左下
SmallRect[2].SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) - Square.Width / 2);
SmallRect[2].SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) + FocusRect.Height - Square.Height / 2);
//下中间
SmallRect[5].SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) + (FocusRect.Width - Square.Width) / 2);
SmallRect[5].SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) + FocusRect.Height - Square.Height / 2);
//右下
SmallRect[3].SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) + FocusRect.Width - Square.Height / 2);
SmallRect[3].SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) + FocusRect.Height - Square.Height / 2);
//左中间
SmallRect[6].SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) - Square.Width / 2);
SmallRect[6].SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) + (FocusRect.Height - Square.Height) / 2);
//右中间
SmallRect[7].SetValue(Canvas.LeftProperty, (double)FocusRect.GetValue(Canvas.LeftProperty) + FocusRect.Width - Square.Width / 2);
SmallRect[7].SetValue(Canvas.TopProperty, (double)FocusRect.GetValue(Canvas.TopProperty) + (FocusRect.Height - Square.Height) / 2);
}
#endregion
#region 设置鼠标Cursor和相应位置CurrHitPlace
void smallRectangle_MouseEnter(object sender, MouseEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
Hit_Test(element, e.GetPosition(null));
}
/// <summary>
/// 设置鼠标Cursor和相应位置CurrHitPlace
/// </summary>
/// <param name="element"></param>
/// <param name="point"></param>
/// <returns></returns>
public bool Hit_Test(FrameworkElement element, Point point)
{
switch (element.Name)
{
case "SmallRect0":
{
element.Cursor = Cursors.Hand; //.SizeNWSE;
CurrHitPlace = HitDownSquare.HDS_TOPLEFT;
break;
}
case "SmallRect3":
{
element.Cursor = Cursors.Hand;// .SizeNWSE;
CurrHitPlace = HitDownSquare.HDS_BOTTOMRIGHT;
break;
}
case "SmallRect1":
{
element.Cursor = Cursors.Hand;// .SizeNESW;
CurrHitPlace = HitDownSquare.HDS_TOPRIGHT;
break;
}
case "SmallRect2":
{
element.Cursor = Cursors.Hand;// .SizeNESW;
CurrHitPlace = HitDownSquare.HDS_BOTTOMLEFT;
break;
}
case "SmallRect4":
{
element.Cursor = Cursors.SizeNS;
CurrHitPlace = HitDownSquare.HDS_TOP;
break;
}
case "SmallRect5":
{
element.Cursor = Cursors.SizeNS;
CurrHitPlace = HitDownSquare.HDS_BOTTOM;
break;
}
case "SmallRect6":
{
element.Cursor = Cursors.SizeWE;
CurrHitPlace = HitDownSquare.HDS_LEFT;
break;
}
case "SmallRect7":
{
element.Cursor = Cursors.SizeWE;
CurrHitPlace = HitDownSquare.HDS_RIGHT;
break;
}
default:
{
FocusRect.Cursor = Cursors.Arrow;
CurrHitPlace = HitDownSquare.HDS_NONE;
break;
}
}
return true;
}
#endregion
#region 滑动条事件处理代码
/// <summary>
/// 滑动条事件处理代码
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void ViewportSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Slider ZoomInOut = sender as Slider;
if (ZoomInOut.Value >= ZoomInOut.Minimum && imageRatio * ZoomInOut.Value >= ZoomInOut.Minimum)
{
Viewport.Width = ZoomInOut.Value;
Viewport.Height = imageRatio * ZoomInOut.Value;
Viewport.SetValue(Canvas.TopProperty, (double)ViewportHost.GetValue(Canvas.TopProperty) + (ViewportHost.Width - Viewport.Height) / 2);
Viewport.SetValue(Canvas.LeftProperty, (double)ViewportHost.GetValue(Canvas.LeftProperty) + (ViewportHost.Width - Viewport.Width) / 2);
AssureFocusRectZoomInZone(ZoomInOut.Value, ZoomInOut.Minimum);
}
}
#endregion
#region 加载图片流信息并设置宽高比例
/// <summary>
/// 图片的高宽比
/// </summary>
private double imageRatio = 1;
/// <summary>
/// 加载图片文件信息
/// </summary>
/// <param name="fileStream"></param>
public void LoadImageStream(FileStream fileStream, Slider zoomInOut)
{
double width = ViewportHost.Width, height = ViewportHost.Height;
//hack:获取相应的图片高宽信息
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(fileStream);
zoomInOut.Maximum = bitmapImage.PixelWidth;
#region 用获取的图片高宽初始化Viewport,FocusRect区域和以slider
if (bitmapImage.PixelWidth < bitmapImage.PixelHeight)//当图片宽小于高时
{
if (bitmapImage.PixelWidth > width) //当图片宽度超过可视区域的宽度时
{
height = ((double)width / bitmapImage.PixelWidth) * bitmapImage.PixelHeight;
//zoomInOut.Value = (double)width / bitmapImage.PixelWidth;
}
else //未超过时则使用图片的高宽初始化显示区域
{
width = bitmapImage.PixelWidth;
height = bitmapImage.PixelHeight;
}
}
else//当图片高小于宽时
{
if (bitmapImage.PixelHeight > height)//当图片高度超过可视区域的高度时
{
width = ((double)height / bitmapImage.PixelHeight) * bitmapImage.PixelWidth;
//zoomInOut.Value = (double)height / bitmapImage.PixelHeight;
}
else//未超过时则使用图片的高宽初始化显示区域
{
width = bitmapImage.PixelWidth;
height = bitmapImage.PixelHeight;
}
}
Viewport.Width = zoomInOut.Value = width;
Viewport.Height = height;
Viewport.SetValue(Canvas.TopProperty, (double)ViewportHost.GetValue(Canvas.TopProperty) + (ViewportHost.Height - Viewport.Height) / 2);
Viewport.SetValue(Canvas.LeftProperty, (double)ViewportHost.GetValue(Canvas.LeftProperty) + (ViewportHost.Width - Viewport.Width) / 2);
FocusRect.Width = width >= 100 ? 100 : width;
FocusRect.Height = height >= 100 ? 100 : height;
FocusRect.SetValue(Canvas.TopProperty, (double)ViewportHost.GetValue(Canvas.TopProperty) + (ViewportHost.Height - FocusRect.Height) / 2);
FocusRect.SetValue(Canvas.LeftProperty, (double)ViewportHost.GetValue(Canvas.LeftProperty) + (ViewportHost.Width - FocusRect.Width) / 2);
zoomInOut.Minimum = 16;
zoomInOut.ValueChanged += new RoutedPropertyChangedEventHandler<double>(ViewportSlider_ValueChanged);
imageRatio = (double)bitmapImage.PixelHeight / bitmapImage.PixelWidth;
SetRectangles();
#endregion
selectedImage.SetSource(fileStream);
}
#endregion
}
下面是鼠标右键菜单代码(位于ChildWindows\CWViewUploadedImage.xaml),采取动态加载控件方式来加载菜单项并绑定相应事件(如打印):
/// 初始化右键菜单
/// </summary>
void InitPopMenu()
{
Border border = new Border()
{
BorderBrush = new SolidColorBrush(Color.FromArgb(255, 167, 171, 176)),
CornerRadius = new CornerRadius(2),
BorderThickness = new Thickness(1),
Background = new SolidColorBrush(Colors.White),
Effect = new DropShadowEffect() { BlurRadius = 3, Color = Color.FromArgb(255, 230, 227, 236) }
};
StackPanel stackPanel = new StackPanel() { Orientation = Orientation.Vertical };
stackPanel.Children.Insert(0, AddMenuItem("打印头像", "images/print.png", PrintButton_Click));
stackPanel.Children.Insert(1, AddMenuItem("保存到本地", "images/save.png", DownLoadAvatar_Click));
border.Child = stackPanel;
popMenu.Child = border;
}
下面就是菜单项的样式绑定代码:
/// 加载菜单项
/// </summary>
/// <param name="menuName">菜单名称</param>
/// <param name="imageUrl">图片</param>
/// <param name="eventHandler">处理事件</param>
/// <returns></returns>
Grid AddMenuItem(string menuName, string imageUrl, RoutedEventHandler eventHandler)
{
Grid grid = new Grid();// { Margin = new Thickness(1) };
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(25) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(80) });
grid.Children.Add(new Rectangle() { Fill = new SolidColorBrush(Color.FromArgb(255, 233, 238, 238)) });
grid.Children.Add(new Rectangle() { Fill = new SolidColorBrush(Color.FromArgb(255, 226, 228, 231)), HorizontalAlignment = HorizontalAlignment.Right, Width = 1 });
Button roButton = new Button()
{
Height = 22,
Margin = new Thickness(0, 0, 0, 0),
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Top,
HorizontalContentAlignment = HorizontalAlignment.Left,
Style = Application.Current.Resources["ContextMenuButton"] as Style
};
roButton.Click += eventHandler;
Grid.SetColumnSpan(roButton, 2);
StackPanel sp = new StackPanel() { Orientation = Orientation.Horizontal };
Image roImage = new Image() { HorizontalAlignment = HorizontalAlignment.Left, Width = 16, Height = 16, Margin = new Thickness(1, 0, 0, 0) };
roImage.Source = new BitmapImage(new Uri("/HaoRan.WebCam;component/" + imageUrl, UriKind.RelativeOrAbsolute));
sp.Children.Add(roImage);
sp.Children.Add(new TextBlock() { HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(16, 0, 0, 0), Text = menuName });
roButton.Content = sp;
grid.Children.Add(roButton);
return grid;
}
接下来就是用户选择下载或打印的实现代码(里面的JpegHelper类是一个将WriteableBitmap转为jpeg图片的辅助类):
/// 保存到本地
/// </summary>
private void DownLoadAvatar_Click(object sender, RoutedEventArgs e)
{
if (saveFileDlg.ShowDialog().Value)
{
using (Stream dstStream = saveFileDlg.OpenFile())
{
try
{
Image image;
double Size = FocusWidth > FocusHeight ? FocusWidth : FocusHeight;//hack:将高宽转为size,这样就可以将ui元素中的内容保存到本地了
if (popMenu.Tag.ToString() == "LargeImageScrollViewer")
image = new Image() { Width = Size, Height = Size, Source = LargeImage.Source };
else if (popMenu.Tag.ToString() == "MediumImageScrollViewer")
image = new Image() { Width = Size * 0.8, Height = Size * 0.8, Source = MediumImage.Source };
else
image = new Image() { Width = Size * 0.6, Height = Size * 0.6, Source = SmallImage.Source };
WriteableBitmap bmp = new WriteableBitmap(image, null);
JpegHelper.EncodeJpeg(bmp, dstStream);
}
catch (Exception ex)
{
Utils.ShowMessageBox("Error saving snapshot", ex.Message);
}
}
}
}
下面是打印代码:
/// <summary>
/// 点击打印按钮事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PrintButton_Click(object sender, RoutedEventArgs e)
{
PrintDocument doc = new PrintDocument() {};
//doc.StartPrint += new EventHandler<StartPrintEventArgs>(doc_StartPrint);
doc.EndPrint += OnEndPrint;
doc.PrintPage += new EventHandler<PrintPageEventArgs>(doc_PrintPage);
doc.Print("打印头像");
}
/// <summary>
/// 打印处理代码
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void doc_PrintPage(object sender, PrintPageEventArgs e)
{
PrintImage.Height = FocusHeight;
PrintImage.Width = FocusWidth;
if (popMenu.Tag.ToString() == "MediumImageScrollViewer")
{
PrintImage.Height *= 0.8;
PrintImage.Width *= 0.8;
}
else if (popMenu.Tag.ToString() == "SmallImageScrollViewer")
{
PrintImage.Height *= 0.6;
PrintImage.Width *= 0.6;
}
ImageInf.Text = "头像类型:" + popMenu.Tag.ToString().Replace("ScrollViewer", "") + " 宽:" + PrintImage.Width + "px 高:" + PrintImage.Height + "px";
AppInf.Text = "Product Details: HaoRan.WebCam Beta2";
PrintArea.Width = e.PrintableArea.Width;
PrintArea.Height = e.PrintableArea.Height;
e.PageVisual = PrintArea;
// 指定是否再次调用另一个页
e.HasMorePages = false;
}
Action<Exception> completedCallback = (ex) =>
{
if (ex != null)
{
Utils.ShowMessageBox("打印错误", ex.Message);
}
};
/// <summary>
/// 打印结束事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void OnEndPrint(object sender, EndPrintEventArgs e)
{
if (completedCallback != null)
{
completedCallback(e.Error);
}
}
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
throw new NotImplementedException();
}
#endregion
下面是使用Silverlight4摄像头的代码(WebCam.xaml.cs):
/// WebCam页
/// </summary>
public partial class WebCam : Page
{
/// <summary>
/// 初始化视频捕捉设备
/// </summary>
private CaptureSource captureSource = new CaptureSource()
{
VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice(),
AudioCaptureDevice = CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice()
};
/// <summary>
/// 保存文件对话框
/// </summary>
private SaveFileDialog saveFileDlg = new SaveFileDialog
{
DefaultExt = ".jpg",
Filter = "JPEG Images (*jpeg *.jpg)|*.jpeg;*.jpg",
};
public WebCam()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(WebCam_Loaded);
}
void WebCam_Loaded(object sender, RoutedEventArgs e)
{
BtnUploadImage.IsEnabled = BtnAdvanceMode.IsEnabled = false;
BtnCapture.IsEnabled = goBack.IsEnabled = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice() != null;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{}
/// <summary>
/// 捕捉图像信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnCapture_Click(object sender, RoutedEventArgs e)
{
try
{ // 开始捕捉
if (captureSource.State != CaptureState.Started)
{
captureSource.Stop();
// 创建 video brush 并填充到 rectangle
VideoBrush vidBrush = new VideoBrush();
vidBrush.Stretch = Stretch.UniformToFill;
vidBrush.SetSource(captureSource);
focusRectangle.Viewport.Fill = vidBrush;
// 询问是否接入
if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
{
focusRectangle.Viewport.MaxHeight = focusRectangle.Viewport.MaxWidth = ZoomInOut.Maximum = 400;
ZoomInOut.Value = 270;
ZoomInOut.Minimum = 16;
ZoomInOut.ValueChanged += new RoutedPropertyChangedEventHandler<double>(focusRectangle.ViewportSlider_ValueChanged);
captureSource.Start();
BtnCapture.Text = "打开摄像头";
BtnUploadImage.IsEnabled = BtnAdvanceMode.IsEnabled = true;
}
}
else
{
captureSource.Stop();
BtnCapture.Text = "关闭摄像头";
BtnUploadImage.IsEnabled = BtnAdvanceMode.IsEnabled = false;
}
}
catch (Exception ex)
{
Utils.ShowMessageBox("Error using webcam", ex.Message);
}
}
/// <summary>
/// 上传头像
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnUploadImage_Click(object sender, RoutedEventArgs e)
{
captureSource.Stop();
Utils.UploadUserFile(Utils.GetUserId() + ".jpg", focusRectangle.imageScroll, focusRectangle.FocusRect,
//定制UserFile的PropertyChanged 属性,如BytesUploaded,Percentage,IsDeleted
new System.ComponentModel.PropertyChangedEventHandler(FileRowControl_PropertyChanged));
}
/// <summary>
/// 上传文件进度属性事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void FileRowControl_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
UserFile userFile = sender as UserFile;
if (e.PropertyName == "Percentage")
{
Percentage.Value = userFile.Percentage;
Percentage.Visibility = Percentage.Value == 100 ? Visibility.Collapsed : Visibility.Visible;
}
//当前文件上传完毕
if (userFile.State == Constants.FileStates.Finished)
{
CWViewUploadedImage cw = new CWViewUploadedImage();
cw.Closed += (o, eventArgs) =>
{
if (cw.DialogResult == true)//确定并就隐藏当前sl应用窗口
NavPage.javaScriptableObject.OnCloseAvatar(null); //调用js端注册事件
//Utils.ShowMessageBox("op: 确定并就隐藏当前sl应用窗口");
};
cw.LargeImageWidth.Text = focusRectangle.FocusRect.Width.ToString();
cw.LargeImageHeight.Text = focusRectangle.FocusRect.Height.ToString().ToString();
cw.Show();
captureSource.Start();
}
}
/// <summary>
/// 返回上一页
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void goBack_Click(object sender, RoutedEventArgs e)
{
this.NavigationService.GoBack();
}
#region 高级模式事件代码
/// <summary>
/// 高级模式事件代码
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnAdvanceMode_Click(object sender, RoutedEventArgs e)
{
captureSource.Stop();
Utils.UploadUserFile(Utils.GetUserId() + ".jpg", focusRectangle.imageScroll, focusRectangle.FocusRect,
(o, eventArgs) => //定制UserFile的PropertyChanged 属性,如BytesUploaded,Percentage,IsDeleted
{
UserFile userFile = o as UserFile;
if (eventArgs.PropertyName == "Percentage")
{
Percentage.Value = userFile.Percentage;
Percentage.Visibility = Percentage.Value == 100 ? Visibility.Collapsed : Visibility.Visible;
}
//当前文件上传完毕
if (userFile.State == Constants.FileStates.Finished)
this.NavigationService.Navigate(
new Uri(
string.Format("/AdvanceMode?focusWidth={0}&focusHeight={1}&fileName={2}",
focusRectangle.FocusRect.Width,
focusRectangle.FocusRect.Height,
userFile.FileName),
UriKind.Relative));
});
}
#endregion
}
下面是涂鸦功能中的工具栏XMAL和实现代码,如下图:
InkMenu.xaml:
<!--InkPresenter Start-->
<StackPanel Margin="0,0,8,0" Canvas.Top="5">
<TextBlock FontSize="12" Name="stroke">边框色:</TextBlock>
<Slider Name="inkStrokeSlider" Minimum="0" Maximum="1" Width="100" Height="20" HorizontalAlignment="Left" Orientation="Horizontal" ValueChanged="inkStrokeSlider_ValueChanged">
<Slider.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0" >
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFF0000" Offset="0.143"/>
<GradientStop Color="#FF00FF00" Offset="0.286"/>
<GradientStop Color="#FF0000FF" Offset="0.429"/>
<GradientStop Color="#FF00FFFF" Offset="0.571"/>
<GradientStop Color="#FFFF00FF" Offset="0.714"/>
<GradientStop Color="#FFFFFF00" Offset="0.857"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</LinearGradientBrush>
</Slider.Background>
</Slider>
<TextBlock FontSize="12" >填充色:</TextBlock>
<Slider Name="inkFillSlider" Minimum="0" Maximum="1" Width="100" Height="20" HorizontalAlignment="Left" Orientation="Horizontal" ValueChanged="inkFillSlider_ValueChanged">
<Slider.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0" >
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFFF0000" Offset="0.143"/>
<GradientStop Color="#FF00FF00" Offset="0.286"/>
<GradientStop Color="#FF0000FF" Offset="0.429"/>
<GradientStop Color="#FF00FFFF" Offset="0.571"/>
<GradientStop Color="#FFFF00FF" Offset="0.714"/>
<GradientStop Color="#FFFFFF00" Offset="0.857"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</LinearGradientBrush>
</Slider.Background>
</Slider>
<TextBlock FontSize="12" >边框:</TextBlock>
<Slider Name="inkThicknessSlider" Minimum="0" Maximum="1" Width="100" Height="20" HorizontalAlignment="Left" Orientation="Horizontal" ValueChanged="inkThicknessSlider_ValueChanged" />
<TextBlock FontSize="12" >透明:</TextBlock>
<Slider Name="inkTransparencySlider" Minimum="0" Maximum="1" Width="100" Height="20" HorizontalAlignment="Left" Orientation="Horizontal" ValueChanged="inkTransparencySlider_ValueChanged" />
<TextBlock Canvas.Left="10" Canvas.Top="200" FontSize="12" >预览:</TextBlock>
<InkPresenter x:Name="inkPreview" Canvas.Top="215" Canvas.Left="15" Width="100" Height="35">
<InkPresenter.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Gray" Offset="0"/>
<GradientStop Color="Snow" Offset="1"/>
</LinearGradientBrush>
</InkPresenter.Background>
<InkPresenter.Strokes>
<StrokeCollection>
<Stroke>
<Stroke.DrawingAttributes>
<DrawingAttributes Color="Black" OutlineColor="Black" Height="5" Width="5"/>
</Stroke.DrawingAttributes>
<Stroke.StylusPoints>
<StylusPointCollection>
<StylusPoint X="6.365068435668945" Y="13.124124526977539"/>
<StylusPoint X="6.365068435668945" Y="13.124124526977539" />
<StylusPoint X="6.414070129394531" Y="13.76108169555664" />
<StylusPoint X="6.414070129394531" Y="13.76108169555664" />
<StylusPoint X="7.002099990844727" Y="14.153057098388671" />
<StylusPoint X="7.590129852294922" Y="14.104059219360351" />
<StylusPoint X="8.423171997070312" Y="13.859075546264648" />
<StylusPoint X="9.501224517822265" Y="13.46710205078125" />
<StylusPoint X="10.922296524047851" Y="12.830144882202148" />
<StylusPoint X="12.58837890625" Y="12.046195983886718" />
<StylusPoint X="14.401470184326171" Y="11.017265319824218" />
<StylusPoint X="16.41057014465332" Y="10.037330627441406" />
<StylusPoint X="18.41967010498047" Y="8.910406112670898" />
<StylusPoint X="20.526775360107422" Y="7.73448371887207" />
<StylusPoint X="22.437870025634765" Y="6.70555305480957" />
<StylusPoint X="24.299964904785156" Y="5.725618362426758" />
<StylusPoint X="25.770038604736328" Y="4.941671371459961" />
<StylusPoint X="25.770038604736328" Y="4.941671371459961" />
<StylusPoint X="27.19110870361328" Y="4.206720352172852" />
<StylusPoint X="28.171157836914062" Y="3.7167530059814453" />
<StylusPoint X="29.102203369140625" Y="3.2757816314697265" />
<StylusPoint X="29.690235137939453" Y="2.981801986694336" />
<StylusPoint X="29.690235137939453" Y="2.981801986694336" />
<StylusPoint X="30.278263092041015" Y="2.736818313598633" />
<StylusPoint X="30.278263092041015" Y="2.736818313598633" />
<StylusPoint X="30.278263092041015" Y="2.736818313598633" />
<StylusPoint X="30.033252716064453" Y="3.324777603149414" />
<StylusPoint X="29.837242126464843" Y="3.765748977661133" />
<StylusPoint X="29.298213958740234" Y="4.59869384765625" />
<StylusPoint X="28.75918960571289" Y="5.67662239074707" />
<StylusPoint X="27.975147247314453" Y="7.195520401000977" />
<StylusPoint X="27.2401123046875" Y="8.861410140991211" />
<StylusPoint X="26.35806655883789" Y="10.821279525756836" />
<StylusPoint X="25.5250244140625" Y="12.830144882202148" />
<StylusPoint X="24.789989471435547" Y="14.790014266967773" />
<StylusPoint X="24.201961517333984" Y="16.65188980102539" />
<StylusPoint X="23.858943939208984" Y="18.317779541015625" />
<StylusPoint X="23.809940338134765" Y="19.689685821533203" />
<StylusPoint X="24.103954315185547" Y="20.522632598876953" />
<StylusPoint X="24.740985870361328" Y="20.91460418701172" />
<StylusPoint X="25.770038604736328" Y="20.91460418701172" />
<StylusPoint X="27.28911590576172" Y="20.375640869140625" />
<StylusPoint X="29.200210571289062" Y="19.395706176757812" />
<StylusPoint X="29.200210571289062" Y="19.395706176757812" />
<StylusPoint X="31.356319427490234" Y="18.072795867919922" />
<StylusPoint X="33.70843505859375" Y="16.455902099609375" />
<StylusPoint X="36.20756149291992" Y="14.594026565551757" />
<StylusPoint X="38.75568771362305" Y="12.683155059814453" />
<StylusPoint X="41.15680694580078" Y="10.772281646728515" />
<StylusPoint X="41.15680694580078" Y="10.772281646728515" />
<StylusPoint X="43.410919189453125" Y="8.910406112670898" />
<StylusPoint X="45.273014068603516" Y="7.391508102416992" />
<StylusPoint X="46.74308776855469" Y="6.117591857910156" />
<StylusPoint X="47.82114028930664" Y="5.186655044555664" />
<StylusPoint X="48.55617904663086" Y="4.696687698364258" />
<StylusPoint X="48.55617904663086" Y="4.696687698364258" />
<StylusPoint X="48.55617904663086" Y="4.696687698364258" />
<StylusPoint X="48.55617904663086" Y="5.725618362426758" />
<StylusPoint X="47.91914749145508" Y="6.999532699584961" />
<StylusPoint X="47.08610534667969" Y="8.46943473815918" />
<StylusPoint X="46.05705261230469" Y="10.33131217956543" />
<StylusPoint X="44.979000091552734" Y="12.340177536010742" />
<StylusPoint X="44.979000091552734" Y="12.340177536010742" />
<StylusPoint X="43.85194396972656" Y="14.398040771484375" />
<StylusPoint X="42.82289123535156" Y="16.406906127929687" />
<StylusPoint X="42.82289123535156" Y="16.406906127929687" />
<StylusPoint X="41.94084548950195" Y="18.219783782958984" />
<StylusPoint X="41.30381393432617" Y="19.88567352294922" />
<StylusPoint X="41.30381393432617" Y="19.88567352294922" />
<StylusPoint X="40.91179656982422" Y="21.159587860107422" />
<StylusPoint X="40.86279296875" Y="22.139522552490234" />
<StylusPoint X="41.15680694580078" Y="22.62948989868164" />
<StylusPoint X="41.74483871459961" Y="22.72748565673828" />
<StylusPoint X="42.67588424682617" Y="22.33551025390625" />
<StylusPoint X="43.85194396972656" Y="21.60055923461914" />
<StylusPoint X="45.37101745605469" Y="20.620624542236328" />
<StylusPoint X="47.03710174560547" Y="19.297714233398437" />
<StylusPoint X="48.85019302368164" Y="17.82781219482422" />
<StylusPoint X="50.71228790283203" Y="16.161922454833984" />
<StylusPoint X="52.574378967285156" Y="14.54503059387207" />
<StylusPoint X="54.43647003173828" Y="12.928138732910156" />
<StylusPoint X="56.2005615234375" Y="11.605226516723632" />
<StylusPoint X="56.2005615234375" Y="11.605226516723632" />
<StylusPoint X="57.81764221191406" Y="10.380308151245117" />
<StylusPoint X="59.140708923339844" Y="9.449369430541992" />
<StylusPoint X="60.21875762939453" Y="8.763416290283203" />
<StylusPoint X="61.100807189941406" Y="8.371442794799804" />
<StylusPoint X="61.73783874511719" Y="8.371442794799804" />
<StylusPoint X="61.73783874511719" Y="8.371442794799804" />
<StylusPoint X="62.22785949707031" Y="9.498367309570312" />
<StylusPoint X="62.08085632324219" Y="10.62529182434082" />
<StylusPoint X="61.68883514404297" Y="12.242183685302734" />
<StylusPoint X="61.100807189941406" Y="14.251049041748046" />
<StylusPoint X="60.36576843261719" Y="16.602893829345703" />
<StylusPoint X="59.53273010253906" Y="19.15072250366211" />
<StylusPoint X="58.65068054199219" Y="21.74755096435547" />
<StylusPoint X="57.81764221191406" Y="24.246383666992187" />
<StylusPoint X="57.082603454589844" Y="26.69622039794922" />
<StylusPoint X="56.5435791015625" Y="28.75408172607422" />
<StylusPoint X="56.29856872558594" Y="30.419971466064453" />
<StylusPoint X="56.347564697265625" Y="31.497901916503906" />
<StylusPoint X="56.78858947753906" Y="31.93886947631836" />
<StylusPoint X="57.5726318359375" Y="31.791881561279297" />
<StylusPoint X="58.797691345214844" Y="31.20391845703125" />
<StylusPoint X="60.36576843261719" Y="30.17498779296875" />
<StylusPoint X="62.42387390136719" Y="28.70508575439453" />
<StylusPoint X="64.62898254394531" Y="27.039196014404297" />
<StylusPoint X="66.9811019897461" Y="25.079326629638672" />
<StylusPoint X="69.43122100830078" Y="23.119457244873047" />
<StylusPoint X="71.83234405517578" Y="21.257583618164062" />
<StylusPoint X="74.18445587158203" Y="19.54269790649414" />
<StylusPoint X="76.38957214355469" Y="18.072795867919922" />
<StylusPoint X="78.34967041015625" Y="16.847877502441406" />
<StylusPoint X="78.34967041015625" Y="16.847877502441406" />
<StylusPoint X="79.96675109863281" Y="15.916938781738281" />
<StylusPoint X="81.33881378173828" Y="15.27998161315918" />
<StylusPoint X="82.36786651611328" Y="14.986000061035156" />
<StylusPoint X="83.15190887451172" Y="15.083993911743164" />
<StylusPoint X="83.64192962646484" Y="15.57396125793457" />
<StylusPoint X="83.7889404296875" Y="16.504899978637695" />
<StylusPoint X="83.49492645263672" Y="17.77881622314453" />
<StylusPoint X="83.00489807128906" Y="19.4447021484375" />
<StylusPoint X="82.31886291503906" Y="21.208587646484375" />
<StylusPoint X="81.53482818603515" Y="23.16845703125" />
<StylusPoint X="80.75078582763672" Y="25.030330657958984" />
<StylusPoint X="79.96675109863281" Y="26.843212127685547" />
</StylusPointCollection>
</Stroke.StylusPoints>
</Stroke>
</StrokeCollection>
</InkPresenter.Strokes>
</InkPresenter>
<CheckBox Name="Erase" Content="橡皮擦" ToolTipService.ToolTip="选中后可擦除指定画笔" />
<!--InkPresenter End-->
</StackPanel>
</Canvas>
InkMenu.xaml.cs:
{
public InkMenu()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(InkMenu_Loaded);
}
void InkMenu_Loaded(object sender, RoutedEventArgs e)
{
inkAttributes = inkPreview.Strokes[0].DrawingAttributes;
inkAttributes.Color = GetColor(inkFillSlider.Value);
inkAttributes.OutlineColor = GetColor(inkStrokeSlider.Value);
inkAttributes.Width = inkAttributes.Height = inkThicknessSlider.Value * 10d;
}
#region 橡皮擦点击事件
/// <summary>
/// 橡皮擦点击事件
/// </summary>
public event RoutedEventHandler Click
{
add
{
Erase.Click += value;
}
remove
{
Erase.Click -= value;
}
}
#endregion
#region 获取颜色值
public DrawingAttributes inkAttributes;
void inkStrokeSlider_ValueChanged(object sender, EventArgs e)
{
byte alpha = inkAttributes.OutlineColor.A;
inkAttributes.Color = GetColor(inkStrokeSlider.Value, alpha);
}
void inkFillSlider_ValueChanged(object sender, EventArgs e)
{
byte alpha = inkAttributes.Color.A;
inkAttributes.Color = GetColor(inkFillSlider.Value, alpha);
}
void inkThicknessSlider_ValueChanged(object sender, EventArgs e)
{
inkAttributes.Width = inkThicknessSlider.Value * 10d;
inkAttributes.Height = inkThicknessSlider.Value * 10d;
}
void inkTransparencySlider_ValueChanged(object sender, EventArgs e)
{
Color color = inkAttributes.Color;
Color outlineColor = inkAttributes.OutlineColor;
inkAttributes.Color = Color.FromArgb((byte)Math.Floor(256d * (1d - inkTransparencySlider.Value)), color.R, color.G, color.B);
inkAttributes.OutlineColor = Color.FromArgb((byte)Math.Floor(256d * (1d - inkTransparencySlider.Value)), outlineColor.R, outlineColor.G, outlineColor.B);
}
/// <summary>
/// 获取颜色值
/// </summary>
/// <returns></returns>
public Color GetColor(double value)
{
return this.GetColor(value, 255);
}
/// <summary>
/// 将滑动条值(Value)转换为ARGB 颜色值并返回
/// </summary>
/// <param name="alpha">alpha通道,该值介于0到255</param>
/// <returns>ARGB 颜色值</returns>
private Color GetColor(double value, byte alpha)
{
Color color;
// 将滑动条的值转换为 ARGB 颜色值
if (value < 0.143d)
{
color = Color.FromArgb(alpha, (byte)Math.Floor((value * 256d) / 0.143d), 0, 0);
}
else if (value < 0.286d)
{
color = Color.FromArgb(alpha, (byte)Math.Floor(256d * (0.286d - value) / 0.143d), (byte)Math.Floor(256d * (value - 0.143d) / 0.143d), 0);
}
else if (value < 0.429)
{
color = Color.FromArgb(alpha, 0, (byte)Math.Floor(256d * (0.429d - value) / 0.143d), (byte)Math.Floor(256d * (value - 0.286d) / 0.143d));
}
else if (value < 0.571)
{
color = Color.FromArgb(alpha, 0, (byte)Math.Floor(256d * (value - 0.429d) / 0.143d), 255);
}
else if (value < 0.714)
{
color = Color.FromArgb(alpha, (byte)Math.Floor(256d * (value - 0.571d) / 0.143d), (byte)Math.Floor(256d * (0.714d - value) / 0.143d), 255);
}
else if (value < 0.857)
{
color = Color.FromArgb(alpha, 255, (byte)Math.Floor(256d * (value - 0.714d) / 0.143d), (byte)Math.Floor(256d * (0.857d - value) / 0.143d));
}
else
{
color = Color.FromArgb(alpha, 255, 255, (byte)Math.Floor(256d * (value - 0.857d) / 0.143d));
}
return color;
}
#endregion
}
另外涂鸭的底层实现代码位于AdvanceMode.xaml.cs中:
/// <summary>
/// Ink 事件代码
/// </summary>
public enum InkEditingMode
{
None,
Ink,
Erase
}
/// <summary>
/// InkEditingMode模式,默认为Ink
/// </summary>
private InkEditingMode editingMode = InkEditingMode.Ink;
private Stroke inkStroke = null;
private StylusPointCollection erasePoints = null;
void onInkPresenterDown(object sender, MouseButtonEventArgs e)
{
if (editingMode == InkEditingMode.None)
return;
(sender as FrameworkElement).CaptureMouse();
StylusPointCollection stylusPoints = e.StylusDevice.GetStylusPoints(InkCanvas);
if (editingMode == InkEditingMode.Erase)
{
erasePoints = new StylusPointCollection();
erasePoints.Add(stylusPoints);
}
else if (editingMode == InkEditingMode.Ink)
{
inkStroke = new Stroke();
inkStroke.StylusPoints.Add(stylusPoints);
inkStroke.DrawingAttributes = new DrawingAttributes();
inkStroke.DrawingAttributes.Color = inkMenu.inkAttributes.Color;
inkStroke.DrawingAttributes.OutlineColor = inkMenu.inkAttributes.OutlineColor;
inkStroke.DrawingAttributes.Width = inkMenu.inkAttributes.Width;
inkStroke.DrawingAttributes.Height = inkMenu.inkAttributes.Height;
InkCanvas.Strokes.Add(inkStroke);
}
}
void SetEditingMode()
{
if (EditInkMode.IsChecked == true)
{
if (inkMenu.Erase.IsChecked == false)
editingMode = InkEditingMode.Ink;
else
editingMode = InkEditingMode.Erase;
}
else
editingMode = InkEditingMode.None;
}
void onInkPresenterMove(object sender, MouseEventArgs e)
{
SetEditingMode();
if (editingMode == InkEditingMode.None) return;
StylusPointCollection stylusPoints = e.StylusDevice.GetStylusPoints(InkCanvas);
if (editingMode == InkEditingMode.Erase)
{
if (erasePoints != null)
{
// hittest and erase
erasePoints.Add(stylusPoints);
StrokeCollection hitStrokes = InkCanvas.Strokes.HitTest(erasePoints);
for (int i = 0; i < hitStrokes.Count; i++)
{
InkCanvas.Strokes.Remove(hitStrokes[i]);
}
}
}
else if (editingMode == InkEditingMode.Ink)
{
if (inkStroke != null)
{
inkStroke.StylusPoints.Add(stylusPoints);
}
}
}
void onInkPresenterEnter(object sender, MouseButtonEventArgs e)
{
if (EditInkMode.IsChecked == true)
{
if (inkMenu.Erase.IsChecked == false)
editingMode = InkEditingMode.Ink;
else
editingMode = InkEditingMode.Erase;
}
else
editingMode = InkEditingMode.None;
erasePoints = null;
inkStroke = null;
}
void onInkPresenterUp(object sender, MouseButtonEventArgs e)
{
if (editingMode == InkEditingMode.None)
return;
if (inkStroke != null)
{
inkStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(InkCanvas));
}
(sender as FrameworkElement).ReleaseMouseCapture();
erasePoints = null;
inkStroke = null;
}
private void EditInkMode_Click(object sender, RoutedEventArgs e)
{
if (EditInkMode.IsChecked == true)
{
inkMenu.Visibility = System.Windows.Visibility.Visible;
if (inkMenu.Erase.IsChecked == false)
editingMode = InkEditingMode.Ink;
else
editingMode = InkEditingMode.Erase;
}
else
{
inkMenu.Visibility = System.Windows.Visibility.Collapsed;
editingMode = InkEditingMode.None;
}
}
private void Erase_Click(object sender, RoutedEventArgs e)
{
inkMenu.Visibility = System.Windows.Visibility.Visible;
if (inkMenu.Erase.IsChecked == false)
editingMode = InkEditingMode.Ink;
else
editingMode = InkEditingMode.Erase;
}
#endregion
当然就目前产品代码的结构而言还不够优化,特别是重复的代码段还有一些,不过不影响大家的最终使用,鉴于目前本人的经历和时间有限,所以就把它开源出来,大家如果感兴趣可以在其基础上加入更新的功能来完善它,呵呵。
好了,今天的内容就先到这里了, 源码下载链接,请点击这里。
相关链接:
目前为止功能最全的基于silverlight4(beta)的摄像头应用
基于silverlight4(beta)的摄像头应用(Beta2)发布
原文链接: http://www.cnblogs.com/daizhj/archive/2010/08/31/1813437.html
作者: daizhj, 代震军
Tags: silverlight,webcam