Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在Windows Phone 7中,如何在背景线程上的可写位图上渲染文本?_C#_Multithreading_Silverlight_Windows Phone 7_Writeablebitmap - Fatal编程技术网

C# 在Windows Phone 7中,如何在背景线程上的可写位图上渲染文本?

C# 在Windows Phone 7中,如何在背景线程上的可写位图上渲染文本?,c#,multithreading,silverlight,windows-phone-7,writeablebitmap,C#,Multithreading,Silverlight,Windows Phone 7,Writeablebitmap,我正在尝试在WindowsPhone7应用程序中渲染位图上的文本 在主线程上运行时,看起来或多或少类似于以下内容的代码可以正常工作: public ImageSource RenderText(string text, double x, double y) { var canvas = new Canvas(); var textBlock = new TextBlock { Text = text }; canvas.Children.Add(textBloxk);

我正在尝试在WindowsPhone7应用程序中渲染位图上的文本

在主线程上运行时,看起来或多或少类似于以下内容的代码可以正常工作:

public ImageSource RenderText(string text, double x, double y)
{
    var canvas = new Canvas();

    var textBlock = new TextBlock { Text = text };
    canvas.Children.Add(textBloxk);
    Canvas.SetLeft(textBlock, x);
    Canvas.SetTop(textBlock, y);

    var bitmap = new WriteableBitmap(400, 400);
    bitmap.Render(canvas, null);
    bitmap.Invalidate();
    return bitmap;
}
现在,由于我必须使用更复杂的内容渲染多个图像,因此我希望在后台线程上渲染位图,以避免出现无响应的UI

当我使用
BackgroundWorker
执行此操作时,
TextBlock
的构造函数抛出一个
UnauthorizedAccessException
声明这是一个无效的跨线程访问

我的问题是:如何在不阻塞UI的情况下在位图上呈现文本

  • 请不要建议使用web服务进行渲染。我需要渲染大量图像,带宽成本不能满足我的需要,离线工作能力是一项主要要求
  • 如果有其他方式呈现文本,则解决方案不一定要使用
    WriteableBitmap
    UIElements
编辑

另一个想法:是否有人知道是否可以在另一个线程中运行UI消息循环,然后让该线程完成工作?(而不是使用
后台工作人员

编辑2

考虑“代码> > Wraveabl位图< /代码>的替代品,我需要的特性是:

  • 绘制背景图像
  • 在给定字体系列和大小(最好是样式)的情况下,测量一行字符串的宽度和高度。不需要字包装
  • 在给定坐标处绘制具有给定字体系列、大小和样式的单线字符串
  • 文本呈现应支持透明背景。也就是说,你应该看到字符之间的背景图像

首先,您确定要将其渲染为位图吗?用图像和文本块生成一个
画布如何

我需要渲染大量图像

我有一种感觉,这将扼杀手机的性能。通常,对于位图维护,最好的方法是使用XNA。XNA框架的某些部分在Silverlight项目中做得非常好。(顺便说一句,Silverlight和XNA将在同一项目中共存)

我会退一步想想这个功能。像这样发展一个星期,然后以不可接受的表现结束,会让我成为一只悲伤的熊猫

编辑

据我所知,你需要一些弹出式的图像作为背景和信息

使用TextBlock制作画布,但将其隐藏

<Canvas x:Name="userInfoCanvas"  Height="200" Width="200" Visibility="Collapsed">
    <Image x:Name="backgroundImage"> </Image>
    <TextBlock x:Name="messageTextBlock" Canvas.ZIndex="3> </TextBlock> <!--ZIndex set the order of elements  -->
</Canvas>
很明显,这里有一个更新问题。UIelements只能从UI线程进行更新,因此更新必须使用调度程序进行排队

Dispatcher.BeginInvoke(DispatcherPriority.Background, messageUpdate);  //messageUpdate is an Action or anthing that can be infered to Delegate

PS.没有编译,这是更多的伪代码。

UI元素的本质要求在UI线程上与它们交互。即使您可以在后台线程上创建它们,当您尝试将它们渲染到WriteableBitmap中时,您也会得到类似的异常,即使它允许您这样做,元素在添加到可视化树中之前实际上不会有可视化表示。您可能需要使用通用图像处理库,而不是使用UI元素


也许您可以更广泛地描述您的场景,我们可能会为您提供更好的解决方案:)

我同意Derek的回答:您试图在没有UI的情况下使用UI控件

如果要渲染位图,则需要使用用于在位图上绘制文本的类

我认为WindowsPhone7具有.NETCompact框架

psudeo代码:

public Bitmap RenderText(string text, double x, double y)
{
   Bitmap bitmap = new Bitmap(400, 400);

   using (Graphics g = new Graphics(bitmap))
   {
      using (Font font = SystemFonts....)
      {
         using (Brush brush = new SolidColorBrush(...))
         {
            g.DrawString(text, font, brush, new Point(x, y));
         }
      }
   }

   return bitmap;
}

我不确定这是否能完全解决您的问题,但我在我的漫画书阅读器中使用了两种工具(我不会无耻地把它插在这里,但我很受诱惑……如果您正在搜索它,我会给您一个提示……这是“惊人的”)。有时我需要将一组图像缝合在一起。我使用Rene Schulte(和其他一些贡献者)的WriteableBitmapExtensions()。我已经能够将图像的渲染/缝合卸载到背景线程,然后将生成的WriteableBitmap设置为UI线程上某些图像的源

这个领域的另一个后起之秀是.NET映像工具()。它们有一系列用于保存/读取各种图像格式的实用程序。它们也有一些低级别,我希望有一个简单的方法来使用它们(但现在没有)

以上所有工作都在WP7中完成


我想主要的区别在于,使用这些工具,您将不会使用XAML,而是直接向图像中写入内容(因此您可能需要对文本等进行大小检测)。

此方法从预先制作的图像中复制字母,而不是使用TextBlock,它基于我对此的回答。主要限制是需要为所需的每种字体和大小使用不同的图像。大小为20的字体需要大约150kb

使用导出所需大小的字体和xml度量文件。代码假定它们的名称为“FontName FontSize”.png和“FontName FontSize”.xml。将它们添加到项目中,并将构建操作设置为content。该准则还要求:

公共静态类位图字体
{
私有类FontInfo
{
public FontInfo(WriteableBitmap图像、字典度量、整数大小)
{
这个。图像=图像;
这个。度量=度量;
这个。大小=大小;
}
公共可写位图映像{get;private set;}
公共字典度量{get;private set;}
公共整数大小{get;私有集;}
}
私有静态字典字体=新建字典();
公共静态无效注册表项(字符串名称,参数int[]大小)
{
foreach(变量大小,以大小为单位)
{
字符串fontFile=name+“”+size+“.png”;
字符串fontMetricsFile=name+“”+size+“.xml”;
public Bitmap RenderText(string text, double x, double y)
{
   Bitmap bitmap = new Bitmap(400, 400);

   using (Graphics g = new Graphics(bitmap))
   {
      using (Font font = SystemFonts....)
      {
         using (Brush brush = new SolidColorBrush(...))
         {
            g.DrawString(text, font, brush, new Point(x, y));
         }
      }
   }

   return bitmap;
}
public static class BitmapFont
{
    private class FontInfo
    {
        public FontInfo(WriteableBitmap image, Dictionary<char, Rect> metrics, int size)
        {
            this.Image = image;
            this.Metrics = metrics;
            this.Size = size;
        }
        public WriteableBitmap Image { get; private set; }
        public Dictionary<char, Rect> Metrics { get; private set; }
        public int Size { get; private set; }
    }

    private static Dictionary<string, List<FontInfo>> fonts = new Dictionary<string, List<FontInfo>>();
    public static void RegisterFont(string name,params int[] sizes)
    {
        foreach (var size in sizes)
        {
            string fontFile = name + " " + size + ".png";
            string fontMetricsFile = name + " " + size + ".xml";
            BitmapImage image = new BitmapImage();

            image.SetSource(App.GetResourceStream(new Uri(fontFile, UriKind.Relative)).Stream);
            var metrics = XDocument.Load(fontMetricsFile);
            var dict = (from c in metrics.Root.Elements()
                        let key = (char) ((int) c.Attribute("key"))
                        let rect = new Rect((int) c.Element("x"), (int) c.Element("y"), (int) c.Element("width"), (int) c.Element("height"))
                        select new {Char = key, Metrics = rect}).ToDictionary(x => x.Char, x => x.Metrics);

            var fontInfo = new FontInfo(new WriteableBitmap(image), dict, size);

            if(fonts.ContainsKey(name))
                fonts[name].Add(fontInfo);
            else
                fonts.Add(name, new List<FontInfo> {fontInfo});
        }
    }

    private static FontInfo GetNearestFont(string fontName,int size)
    {
        return fonts[fontName].OrderBy(x => Math.Abs(x.Size - size)).First();
    }

    public static Size MeasureString(string text,string fontName,int size)
    {
        var font = GetNearestFont(fontName, size);

        double scale = (double) size / font.Size;

        var letters = text.Select(x => font.Metrics[x]).ToArray();

        return new Size(letters.Sum(x => x.Width * scale),letters.Max(x => x.Height * scale));
    }

    public static void DrawString(this WriteableBitmap bmp,string text,int x,int y, string fontName,int size,Color color)
    {
        var font = GetNearestFont(fontName, size);

        var letters = text.Select(f => font.Metrics[f]).ToArray();

        double scale = (double)size / font.Size;

        double destX = x;
        foreach (var letter in letters)
        {
            var destRect = new Rect(destX,y,letter.Width * scale,letter.Height * scale);
            bmp.Blit(destRect, font.Image, letter, color, WriteableBitmapExtensions.BlendMode.Alpha);
            destX += destRect.Width;
        }
    }
}