2

我创建了一个后台代理来更新我的动态磁贴。代理调度和执行正常,但代理执行的代码成为问题 - 它根本无法完全执行并且没有提供任何错误。据我所知,我使用的 API 没有受限,除非 Cimbalino 工具包以某种方式提供了问题,即使我使用的是 NuGet 的后台代理特定版本。

当 RenderText() 和 RenderTextWide() 无法运行时,代码似乎停止执行。没有提供错误。在前台应用程序中运行时,相同的代码可以正常工作。

using System;
using System.Windows;
using Microsoft.Phone.Scheduler;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Info;
using Cimbalino.Phone.Toolkit;
using System.Linq;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows.Controls;
using System.IO.IsolatedStorage;
using Cimbalino.Phone.Toolkit.Extensions;

namespace ScheduledTaskAgent1
{
    public class ScheduledAgent : ScheduledTaskAgent
    {
        private static volatile bool _classInitialized;

        public ScheduledAgent()
        {
            if (!_classInitialized)
            {
                _classInitialized = true;
                // Subscribe to the managed exception handler
                Deployment.Current.Dispatcher.BeginInvoke(delegate
                {
                    Application.Current.UnhandledException += ScheduledAgent_UnhandledException;
                });
            }
        }

        /// Code to execute on Unhandled Exceptions
        private void ScheduledAgent_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                System.Diagnostics.Debugger.Break();
            }
        }

        //Method to create normal tile image
        private static void RenderText(string currproperty)
        {
            WriteableBitmap b = new WriteableBitmap(336, 336);
            var canvas = new Grid();
            canvas.Width = b.PixelWidth;
            canvas.Height = b.PixelHeight;
            var background = new Canvas();
            background.Height = b.PixelHeight;
            background.Width = b.PixelWidth;

            SolidColorBrush backColor = new SolidColorBrush(Colors.Transparent);
            background.Background = backColor;

            TextBlock currtemp = new TextBlock();
            currtemp.FontSize = 100;
            currtemp.FontFamily = new FontFamily("Segoe UI Light");
            currtemp.FontWeight = FontWeights.Bold;
            currtemp.Foreground = new SolidColorBrush(Colors.White);
            currtemp.Text = currproperty;
            currtemp.Margin = new Thickness(20, 10, 0, 0);
            currtemp.Width = b.PixelWidth - currtemp.Margin.Left * 2;
            canvas.Children.Add(currtemp);

            b.Render(background, null);
            b.Render(canvas, null);
            b.Invalidate();
            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (IsolatedStorageFileStream imageStream = new IsolatedStorageFileStream("/Shared/ShellContent/BackBackgroundImage2.png", System.IO.FileMode.Create, isf))
                {

                    b.SavePng(imageStream);
                }
            }
        }

        //Method to create wide tile image
        private static void RenderTextWide(string currproperty)
        {
            WriteableBitmap b = new WriteableBitmap(691, 336);
            var canvas = new Grid();
            canvas.Width = b.PixelWidth;
            canvas.Height = b.PixelHeight;
            var background = new Canvas();
            background.Height = b.PixelHeight;
            background.Width = b.PixelWidth;

            //Created background color as Accent color
            SolidColorBrush backColor = new SolidColorBrush(Colors.Transparent);
            background.Background = backColor;

            TextBlock currtemp = new TextBlock();
            currtemp.FontSize = 100;
            currtemp.FontFamily = new FontFamily("Segoe UI Light");
            currtemp.FontWeight = FontWeights.Bold;
            currtemp.Foreground = new SolidColorBrush(Colors.White);
            currtemp.Text = currproperty;
            currtemp.Margin = new Thickness(20, 10, 0, 0);
            currtemp.Width = b.PixelWidth - currtemp.Margin.Left * 2;
            canvas.Children.Add(currtemp);

            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (IsolatedStorageFileStream imageStream = new IsolatedStorageFileStream("/Shared/ShellContent/WideBackBackgroundImage2.png", System.IO.FileMode.Create, isf))
                {
                    b.SavePng(imageStream);
                }
            }
        }

        //When task invokes, run the tile update code.
        protected override void OnInvoke(ScheduledTask task)
        {
            ShellTile tile = ShellTile.ActiveTiles.FirstOrDefault();
            if (tile != null)
            {
                FlipTileData flipTile = new FlipTileData();
                flipTile.Title = "";
                flipTile.BackTitle = "Atmosphere";
                RenderText("Test");
                RenderTextWide("Test");
                flipTile.BackBackgroundImage = new Uri("/Assets/NewUI/1.PNG", UriKind.Relative); //Default image for Background Image Medium Tile 336x336 px
                flipTile.BackgroundImage = new Uri(@"isostore:/Shared/ShellContent/BackBackgroundImage2.png", UriKind.Absolute); //Generated image for Back Background 336x336

                flipTile.WideBackBackgroundImage = new Uri("/Assets/NewUI/2.PNG", UriKind.Relative); ////Default image for Background Image Wide Tile 691x336 px
                flipTile.WideBackgroundImage = new Uri(@"isostore:/Shared/ShellContent/WideBackBackgroundImage2.png", UriKind.Absolute);
                tile.Update(flipTile);

                //Tile updated, tell agent operation complete
                NotifyComplete();
            }
        }      
    }
}
4

3 回答 3

3

我刚刚运行了您在附加了调试器的后台代理中共享的代码,问题非常明显 - 它引发了异常!准确地说是无效的跨线程访问异常。所有与 UI 相关的工作都必须发生在 UI 线程和实例化控件中,WriteableBitmaps 就是这样的工作。

解决方案

您需要在适当的线程中使用Deployment.Current.Dispatcher.BeginInvoke来调用RenderText和。RenderTextWide您也可以只调用OnInvokeUI 线程中的所有内容。

注意: Deployment.Current.Dispatcher.BeginInvoke异步调用给定的操作,所以如果你不在 UI 线程上运行所有的东西,你可能需要做一些事情来同步不同的线程。

通知完成

NotifyComplete完成所有工作后,您必须始终致电。基本上你需要做的是 try-catch(all) 然后调用NotifyComplete. 此外,您可能想把它放在ScheduledAgent_UnhandledException以防万一。

NotifyComplete不应该出现if在您的代码中,尽管在 Windows Phone 中该条件始终为真。ShellTile.ActiveTiles始终至少有一个图块 - 主图块 - 即使它没有固定。

调试后台代理

是的,你可以这么做。如果代理不工作,查看问题的最佳方法是启动附加调试器的应用程序,强制调用后台代理并在要检查的代码中设置断点。用于ScheduledActionService.LaunchForTest比正常更快地启动后台代理。

题外话/问题

我可以问一下你想在那个private static volatile bool _classInitialized领域实现什么目标吗?为什么会这样volatile

于 2014-06-24T01:18:40.557 回答
2

从 WP8.0 升级到 WP8.1 Silverlight 后,我​​的应用程序也出现了这个问题。我的计划代理在我的代码中的任意点绝对无声地“崩溃”(生成活动磁贴)。崩溃或挂起经常发生,并且没有抛出异常。我已经断断续续地工作了一个多月,但没有成功。我一直很偏心,以为是我自己造成了这个问题。昨晚我确实找到了可能是解决方案的参考。我还没有在我的应用程序中完全测试它。

在 WP8.1 Silverlight API 更改说明中有一个非常神秘的段落说:

对于能够访问 Silverlight 8.1 功能的托管 Windows Phone 8 ScheduledTaskAgent,它在与 Windows 融合的现代执行堆栈上运行。这使用了与 Windows Phone 8 不同的 CPU 配额机制。在某些情况下,Silverlight 8.1 后台代理可能会发现它获得的 CPU 时间比以前少。如果发生这种情况,应用程序可能会选择调用 RequestAccessAsync()。这将增加分配给代理的 CPU 配额。

我在其他地方发现了一些帖子 ,表明以下代码在添加后台代理任务之前立即解决了一些问题:

await Windows.ApplicationModel.Background.BackgroundExecutionManager.RequestAccessAsync();

我很想听听其他人是否看到这些类型的问题,如果这对他们有帮助。

于 2014-07-14T19:42:07.830 回答
0

解决了!。

我有同样的问题,我用下面的代码解决了:

Deployment.Current.Dispatcher.BeginInvoke(delegate() { RenderText("Test"); }); Deployment.Current.Dispatcher.BeginInvoke(delegate() { RenderTextWide("Test"); });

文件 ScheduledAgent.cs:

    protected override void OnInvoke(ScheduledTask task)
    {
        ShellTile tile = ShellTile.ActiveTiles.FirstOrDefault();
        if (tile != null)
        {
            FlipTileData flipTile = new FlipTileData();
            flipTile.Title = "";
            flipTile.BackTitle = "Atmosphere";

            Deployment.Current.Dispatcher.BeginInvoke(delegate() { RenderText("Test"); });
            Deployment.Current.Dispatcher.BeginInvoke(delegate() { RenderTextWide("Test"); });

            flipTile.BackBackgroundImage = new Uri("/Assets/NewUI/1.PNG", UriKind.Relative); //Default image for Background Image Medium Tile 336x336 px
            flipTile.BackgroundImage = new Uri(@"isostore:/Shared/ShellContent/BackBackgroundImage2.png", UriKind.Absolute); //Generated image for Back Background 336x336

            flipTile.WideBackBackgroundImage = new Uri("/Assets/NewUI/2.PNG", UriKind.Relative); ////Default image for Background Image Wide Tile 691x336 px
            flipTile.WideBackgroundImage = new Uri(@"isostore:/Shared/ShellContent/WideBackBackgroundImage2.png", UriKind.Absolute);
            tile.Update(flipTile);

            //Tile updated, tell agent operation complete
            NotifyComplete();
        }
    }
于 2014-09-04T14:08:20.350 回答