如何在 C# 中为 Windows Metro 风格应用程序在屏幕上绘制?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8099466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to draw on screen for Windows Metro Style Apps in C#?
提问by Crystal
I simply want the user to be able to draw on the screen with some sort of pointer.
我只是希望用户能够使用某种指针在屏幕上绘图。
I already have the code working that captures the pointer's position, but I can't figure out how to place the pixels or shapes or whatever onto the screen.
我已经有了捕获指针位置的代码,但我不知道如何将像素或形状或其他任何东西放置在屏幕上。
I found this useful tutorial:
http://www.dotnetspeaks.com/DisplayArticle.aspx?ID=137
我发现这个有用的教程:http: //www.dotnetspeaks.com/DisplayArticle.aspx?ID=
137
And I've been looking at the documentation here:
http://msdn.microsoft.com/en-us/library/windows/apps/hh465055(v=VS.85).aspx
我一直在查看这里的文档:http:
//msdn.microsoft.com/en-us/library/windows/apps/hh465055(v=VS.85).aspx
No luck so far. =( The tutorial is for Windows Phone 7, so it's a little bit different. =\ Help, please? =)
到目前为止没有运气。=( 本教程适用于 Windows Phone 7,所以有点不同。=\ 请帮忙?=)
And this is what I have so far.
这就是我迄今为止所拥有的。
The drawing part:
绘图部分:
private void Image_PointerPressed(object sender, PointerEventArgs e)
{
Debug.WriteLine("Image_PointerPressed");
isTracing = true;
}
private void Image_PointerReleased(object sender, PointerEventArgs e)
{
Debug.WriteLine("Image_PointerReleased");
isTracing = false;
}
private void Image_PointerMoved(object sender, PointerEventArgs e)
{
Debug.WriteLine("Image_PointerMoved");
Debug.WriteLine(e.GetCurrentPoint(this).Position);
if (isTracing)
{
Debug.WriteLine("isTracing");
Point pos = e.GetCurrentPoint(this).Position;
Color color = Colors.Green;
Line line = new Line() { X1 = pos.X, X2 = pos.X + 1, Y1 = pos.Y, Y2 = pos.Y + 1 };
line.Stroke = new SolidColorBrush(color);
line.StrokeThickness = 15;
//// So how do I draw this line onto the screen?? ////
}
}
For reference, stuff elsewhere in the code:
作为参考,代码中其他地方的内容:
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; using Multimedia.FFmpeg; using Windows.Foundation; using Windows.Storage; using Windows.Storage.Pickers; using Windows.Storage.Streams; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Shapes; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Input; using Windows.UI.Input; bool isTracing = false;
回答by AndrewS
Short form:
简写:
- Add
Line
s andRectangle
s to a panel - Manipulate a bitmap directly
- Use an HTML5 Canvas element in a JavaScript/HTML project
- Write the whole thing in C++/DirectX
- 将
Line
s 和Rectangle
s添加到面板 - 直接操作位图
- 在 JavaScript/HTML 项目中使用 HTML5 Canvas 元素
- 用 C++/DirectX 写整件事
There is no way in Metro/XAML to override an OnRender()
method or the like. Your options are to add existing graphical elements (eg from the Shapes namespace) to a Canvas or other Panel, or to directly manipulate the pixels in a bitmap and push that bitmap into an Image element.
Metro/XAML 无法覆盖OnRender()
方法等。您的选择是将现有的图形元素(例如来自Shapes 命名空间)添加到 Canvas 或其他面板,或者直接操作位图中的像素并将该位图推送到 Image 元素中。
Metro/C# only has retained-mode graphics drawing, which means the only thing it will render is objects that have been added to the view hierarchy. What you're looking for is some kind of immediate-mode graphics drawing, eg
Metro/C# 只有保留模式的图形绘制,这意味着它唯一会渲染的是已添加到视图层次结构中的对象。您正在寻找的是某种即时模式图形绘制,例如
myCanvas.DrawLine( fromPoint, toPoint );
This can be done in a JavaScript/HTML project using HTML5's Canvas object. Which, sadly, is the way I'm leaning for such a project. It's unfortunate that Microsoft is not providing an immediate-mode element for XAML projects but that's the way it is. C++/DirectX is also an option for doing custom drawing but requires a substantial reworking of everything else that you're doing in the app.
这可以在使用HTML5 的 Canvas 对象的 JavaScript/HTML 项目中完成。可悲的是,这就是我倾向于这样一个项目的方式。不幸的是,Microsoft 没有为 XAML 项目提供立即模式元素,但它就是这样。C++/DirectX 也是进行自定义绘图的一种选择,但需要对您在应用程序中执行的所有其他操作进行大量修改。
回答by ch3rryc0ke
Here is a great code sample on how to do this using XAML shapes.
这是关于如何使用 XAML 形状执行此操作的出色代码示例。
回答by Rafael
The main problem in your code is that you're not attaching, the line to any XAML element i suggest you to do it to a Canvas element, more less like this:
您的代码中的主要问题是您没有附加任何 XAML 元素的行,我建议您将其附加到 Canvas 元素,而不是这样:
newCanvas.Children.Add(line);
An alternative is to use Modern Components Drawing Library, it works on WinRT, uses .NET Graphics class like calls and draw directly on a XAML Canvas, note that if you want to save the image as a bitmap, you may need to use also WritableBitmapEx, as XAML Canvas can't be rendered to Bitmaps.
另一种方法是使用Modern Components Drawing Library,它适用于 WinRT,使用 .NET Graphics 类调用并直接在 XAML Canvas 上绘制,请注意,如果要将图像保存为位图,则可能还需要使用WritableBitmapEx,因为 XAML 画布无法呈现为位图。
回答by jem
This sample project has code to draw on screen for Win 8 Store apps in C#/XAML:
此示例项目具有在 C#/XAML 中为 Win 8 Store 应用程序在屏幕上绘制的代码:
http://code.msdn.microsoft.com/windowsapps/Drawing-on-a-Canvas-with-33510ae6
http://code.msdn.microsoft.com/windowsapps/Drawing-on-a-Canvas-with-33510ae6
Here is the relevant C# file:
这是相关的 C# 文件:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Devices.Input;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Input;
using Windows.UI.Input.Inking; //we need to add this name space in order to have many functions
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Shapes;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace DrawingOnCanvasWithInkPen
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
InkManager _inkKhaled = new Windows.UI.Input.Inking.InkManager();
private uint _penID;
private uint _touchID;
private Point _previousContactPt;
private Point currentContactPt;
private double x1;
private double y1;
private double x2;
private double y2;
public MainPage()
{
this.InitializeComponent();
MyCanvas.PointerPressed += new PointerEventHandler(MyCanvas_PointerPressed);
MyCanvas.PointerMoved += new PointerEventHandler(MyCanvas_PointerMoved);
MyCanvas.PointerReleased += new PointerEventHandler(MyCanvas_PointerReleased);
MyCanvas.PointerExited += new PointerEventHandler(MyCanvas_PointerReleased);
}
#region PointerEvents
private void MyCanvas_PointerReleased(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerId == _penID)
{
Windows.UI.Input.PointerPoint pt = e.GetCurrentPoint(MyCanvas);
// Pass the pointer information to the InkManager.
_inkKhaled.ProcessPointerUp(pt);
}
else if (e.Pointer.PointerId == _touchID)
{
// Process touch input
}
_touchID = 0;
_penID = 0;
// Call an application-defined function to render the ink strokes.
e.Handled = true;
}
private void MyCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerId == _penID)
{
PointerPoint pt = e.GetCurrentPoint(MyCanvas);
// Render a red line on the canvas as the pointer moves.
// Distance() is an application-defined function that tests
// whether the pointer has moved far enough to justify
// drawing a new line.
currentContactPt = pt.Position;
x1 = _previousContactPt.X;
y1 = _previousContactPt.Y;
x2 = currentContactPt.X;
y2 = currentContactPt.Y;
if (Distance(x1, y1, x2, y2) > 2.0) // We need to developp this method now
{
Line line = new Line()
{
X1 = x1,
Y1 = y1,
X2 = x2,
Y2 = y2,
StrokeThickness = 4.0,
Stroke = new SolidColorBrush(Colors.Green)
};
_previousContactPt = currentContactPt;
// Draw the line on the canvas by adding the Line object as
// a child of the Canvas object.
MyCanvas.Children.Add(line);
// Pass the pointer information to the InkManager.
_inkKhaled.ProcessPointerUpdate(pt);
}
}
else if (e.Pointer.PointerId == _touchID)
{
// Process touch input
}
}
private double Distance(double x1, double y1, double x2, double y2)
{
double d = 0;
d = Math.Sqrt(Math.Pow((x2 - x1), 2) + Math.Pow((y2 - y1), 2));
return d;
}
private void MyCanvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// Get information about the pointer location.
PointerPoint pt = e.GetCurrentPoint(MyCanvas);
_previousContactPt = pt.Position;
// Accept input only from a pen or mouse with the left button pressed.
PointerDeviceType pointerDevType = e.Pointer.PointerDeviceType;
if (pointerDevType == PointerDeviceType.Pen ||
pointerDevType == PointerDeviceType.Mouse &&
pt.Properties.IsLeftButtonPressed)
{
// Pass the pointer information to the InkManager.
_inkKhaled.ProcessPointerDown(pt);
_penID = pt.PointerId;
e.Handled = true;
}
else if (pointerDevType == PointerDeviceType.Touch)
{
// Process touch input
}
}
#endregion
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
}
}
and xaml file:
和xaml文件:
<Page
x:Class="DrawingOnCanvasWithInkPen.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DrawingOnCanvasWithInkPen"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Canvas Name="MyCanvas" Background="White" HorizontalAlignment="Left" Height="513" Margin="83,102,0,0" VerticalAlignment="Top" Width="1056"/>
</Grid>
In its current state, it only processes pen or mouse input -- but I also got it to work for touch with only slight modifications.
在目前的状态下,它只处理笔或鼠标输入——但我也只需要稍微修改一下就可以用于触摸。
回答by Erno
You should add the Line to a UI element such as a Canvas.
您应该将 Line 添加到 UI 元素,例如 Canvas。