AutoCAD .net Side loading a dwg with ReadDwgFile then Plotting - c#

I used the example here to side load dwgs into memory combined with the example here of Plot From Model Space. I got things working except for the plots are not respecting whether the layers are frozen or not and printing as if they were all thawed. The data coming in from the dwg is correct. I can iterate the layers while debugging and verify the correct ones are either frozen or thawed. Also If I just saveas the dwg to a new name it matches the original concerning the layer state.Any Ideas?
[CommandMethod("PlotLayout")]
public static void PlotLayout()
{
// Get the current document and database, and start a transaction
Document acDoc = Active.Document;
Database acCurDb = Active.Database;
Editor ed = Active.Editor;
var collection = new List<string>() { "C:\\Test\\440001A.dwg", "C:\\Test\\440001B.dwg", "C:\\Test\\440001C.dwg", "C:\\Test\\440001D.dwg" };
for (int i = 0; i < collection.Count; i++)
{
var dwg = collection[i];
var dir = Path.GetDirectoryName(dwg);
var fn = Path.GetFileNameWithoutExtension(dwg);
var filePath = Path.Combine(dir, fn + "-" + i.ToString() + ".pdf");
Database oldDb = HostApplicationServices.WorkingDatabase;
using (Database db = new Database(false, true))
{
db.ReadDwgFile(dwg, FileOpenMode.OpenForReadAndAllShare, false, null);
db.CloseInput(true);
using (Transaction acTrans = db.TransactionManager.StartTransaction())
try
{
HostApplicationServices.WorkingDatabase = db;
LayoutManager acLayoutMgr = LayoutManager.Current;
// Get the current layout and output its name in the Command Line window
Layout acLayout = acTrans.GetObject(acLayoutMgr.GetLayoutId(acLayoutMgr.CurrentLayout),
OpenMode.ForRead) as Layout;
// Get the PlotInfo from the layout
using (PlotInfo acPlInfo = new PlotInfo())
{
acPlInfo.Layout = acLayout.ObjectId;
// Get a copy of the PlotSettings from the layout
using (PlotSettings acPlSet = new PlotSettings(acLayout.ModelType))
{
acPlSet.CopyFrom(acLayout);
// Update the PlotSettings object
PlotSettingsValidator acPlSetVdr = PlotSettingsValidator.Current;
// Set the plot type
acPlSetVdr.SetPlotType(acPlSet, Autodesk.AutoCAD.DatabaseServices.PlotType.Extents);
// Set the plot scale
acPlSetVdr.SetUseStandardScale(acPlSet, true);
acPlSetVdr.SetStdScaleType(acPlSet, StdScaleType.ScaleToFit);
// Center the plot
acPlSetVdr.SetPlotCentered(acPlSet, true);
// Set the plot device to use
acPlSetVdr.SetPlotConfigurationName(acPlSet, "DWF6 ePlot.pc3", "ANSI_B_(11.00_x_17.00_Inches)");
// Set the plot info as an override since it will
// not be saved back to the layout
acPlInfo.OverrideSettings = acPlSet;
// Validate the plot info
using (PlotInfoValidator acPlInfoVdr = new PlotInfoValidator())
{
acPlInfoVdr.MediaMatchingPolicy = MatchingPolicy.MatchEnabled;
acPlInfoVdr.Validate(acPlInfo);
// Check to see if a plot is already in progress
if (PlotFactory.ProcessPlotState == ProcessPlotState.NotPlotting)
{
using (PlotEngine acPlEng = PlotFactory.CreatePublishEngine())
{
// Track the plot progress with a Progress dialog
using (PlotProgressDialog acPlProgDlg = new PlotProgressDialog(false, 1, true))
{
using ((acPlProgDlg))
{
// Define the status messages to display
// when plotting starts
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.DialogTitle, "Plot Progress");
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.CancelJobButtonMessage, "Cancel Job");
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.CancelSheetButtonMessage, "Cancel Sheet");
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.SheetSetProgressCaption, "Sheet Set Progress");
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.SheetProgressCaption, "Sheet Progress");
// Set the plot progress range
acPlProgDlg.LowerPlotProgressRange = 0;
acPlProgDlg.UpperPlotProgressRange = 100;
acPlProgDlg.PlotProgressPos = 0;
// Display the Progress dialog
acPlProgDlg.OnBeginPlot();
acPlProgDlg.IsVisible = true;
// Start to plot the layout
acPlEng.BeginPlot(acPlProgDlg, null);
// Define the plot output
acPlEng.BeginDocument(acPlInfo, acDoc.Name, null, 1, true, "c:\\myplot");
// Display information about the current plot
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.Status, "Plotting: " + acDoc.Name + " - " + acLayout.LayoutName);
// Set the sheet progress range
acPlProgDlg.OnBeginSheet();
acPlProgDlg.LowerSheetProgressRange = 0;
acPlProgDlg.UpperSheetProgressRange = 100;
acPlProgDlg.SheetProgressPos = 0;
// Plot the first sheet/layout
using (PlotPageInfo acPlPageInfo = new PlotPageInfo())
{
acPlEng.BeginPage(acPlPageInfo, acPlInfo, true, null);
}
acPlEng.BeginGenerateGraphics(null);
acPlEng.EndGenerateGraphics(null);
// Finish plotting the sheet/layout
acPlEng.EndPage(null);
acPlProgDlg.SheetProgressPos = 100;
acPlProgDlg.OnEndSheet();
// Finish plotting the document
acPlEng.EndDocument(null);
// Finish the plot
acPlProgDlg.PlotProgressPos = 100;
acPlProgDlg.OnEndPlot();
acPlEng.EndPlot(null);
}
}
}
}
}
}
}
}
catch (System.Exception ex)
{
ed.WriteMessage(ex.ToString());
}
HostApplicationServices.WorkingDatabase = oldDb;
}
}
}

Not ideal but I found a work around. If I iterate the LayerTable, check for frozen then make IsPlottable false it prints correctly. If a better soultion is available please let me know. Thanks
LayerTable _LayerTable = acTrans.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
foreach (ObjectId _LayerTableId in _LayerTable)
{
LayerTableRecord _LayerTableRecord =
(LayerTableRecord)acTrans.GetObject(_LayerTableId,
OpenMode.ForWrite);
if (_LayerTableRecord.IsFrozen)
{
_LayerTableRecord.IsPlottable = false;
}
}

Related

Mongo Tailable cursor not working when trying to run in separate thread

I am trying to use Mongo Tailable cursor in my application I am using below code to create capped collection and tailable cursor
using MongoDB.Bson;
using MongoDB.Driver;
public static class TailableCursor
{
private const string DbUrl = ""//TODO use actual connectionstring
private const string DbName = "Test_App";
private const string CollectionName = "ExchangeMessage";
public static bool CreateCollection()
{
var name = "ExchangeMessage";
var count = 100;
var client = new MongoClient(new MongoUrl(DbUrl));
#pragma warning disable CS0618 // Type or member is obsolete
var server = client.GetServer();
#pragma warning restore CS0618 // Type or member is obsolete
var db = server.GetDatabase(DbName);
if (db == null)
{
return false;
}
if (!db.CollectionExists(name))
{
var options = new CollectionOptionsDocument(new Dictionary<string, object> {
{ "capped", true },
{ "size", count * 1024 },
{ "max", count }
});
db.CreateCollection(name, options);
var collection = db.GetCollection(name);
collection.Insert(new ExchangeMessage());
}
else
{
var collection = db.GetCollection(name);
if (collection.Count() == 0)
{
collection.Insert(new ExchangeMessage());
}
}
server.Disconnect();
return true;
}
public static void SubscribeTailAbleCursor()
{
var client = new MongoClient(new MongoUrl(DbUrl));
var database = client.GetDatabase(DbName);
var collection = database.GetCollection<BsonDocument>(CollectionName);
// Set lastInsertDate to the smallest value possible
BsonValue lastInsertDate = BsonMinKey.Value;
var options = new FindOptions<BsonDocument>
{
// Our cursor is a tailable cursor and informs the server to await
CursorType = CursorType.TailableAwait,
NoCursorTimeout = true
};
// Initially, we don't have a filter. An empty BsonDocument matches everything.
BsonDocument filter = new BsonDocument();
// NOTE: This loops forever. It would be prudent to provide some form of
// an escape condition based on your needs; e.g. the user presses a key.
int i = 0;
while (true)
{
//// Start the cursor and wait for the initial response
//using (var cursor = collection.FindSync(filter, options))
var cursor = collection.FindSync(filter, options);
{
foreach (var document in cursor.ToEnumerable())
{
i++;
// Set the last value we saw
lastInsertDate = document["InsertDate"];
Console.WriteLine(i.ToString());
// Write the document to the console.
Console.WriteLine(document.ToString());
}
}
// The tailable cursor died so loop through and restart it
// Now, we want documents that are strictly greater than the last value we saw
filter = new BsonDocument("$gt", new BsonDocument("InsertDate", lastInsertDate));
}
}
}
//The above code work when called as below from startup or main method but it blocks main //thread
TailableCursor.CreateCollection();
TailableCursor.SubscribeTailAbleCursor();
//When I try to run code in separate thread tailable cursor does not work.
Task.Run(async () =>{
TailableCursor.CreateCollection();
TailableCursor.SubscribeTailAbleCursor();
});

How to split a pdf and preserve thumbnail labels?

I have a pdf that has some pages that need to be removed based on the (thumbnail) label of the page. So, I am using the the PdfCopy.GetImportedPage(...) method to copy only the wanted pages but found that the thumbnail label (page label) gets removed. The only way I am able to add pagelabels is to use a Writer, but then I can't copy pages. Can someone help me here to setup the right construction ?
public Boolean SplitByList(string povDocument, string povOutputDocument, PageLabelList povPageList)
{
PdfReader lorReader = null;
Document lorDocument = null;
PdfCopy lorPdfCopyProvider = null;
PdfImportedPage lorImportedPage = null;
PdfPageLabels lorLbls = null;
try
{
// Intialize a new PdfReader instance with the contents of the source Pdf file:
lorReader = new PdfReader(povDocument);
lorLbls = new PdfPageLabels();
if (povPageList == null || povPageList.GetLength() == 0) return false;
Boolean lbvFirstPage = false;
for (int livCntr = 1; livCntr <= povPageList.GetLength(); livCntr++)
{
PageLabel lorLabel = povPageList.GetItemAt(livCntr);
if (lorLabel != null && lorLabel.lbvPublish)
{
// Do only the first time
if (!lbvFirstPage)
{
lbvFirstPage = true;
lorDocument = new Document(lorReader.GetPageSizeWithRotation(lorLabel.livPageNumber));
// Initialize an instance of the PdfCopyClass with the source document and an output file stream:
lorPdfCopyProvider = new PdfCopy(lorDocument, new System.IO.FileStream(povOutputDocument, System.IO.FileMode.Create));
lorDocument.Open();
}
// Extract the desired page number:
lorImportedPage = lorPdfCopyProvider.GetImportedPage(lorReader, lorLabel.livPageNumber);
lorLbls.AddPageLabel(livCntr, 1, lorLabel.lorPageLabel);
lorPdfCopyProvider.AddPage(lorImportedPage);
}
}
lorPdfCopyProvider.Close();
lorDocument.Close();
lorReader.Close();
return true;
}
catch (Exception ex)
{
lorDocument.Close();
lorReader.Close();
return false;
}
}
This is the page label.

AutoCAD .SendStringToExicute ATTEDIT not selecting selected object

Trying to run ATTEDIT from the Command line after double clicking and have it select the previously selected item. I've intercepted the double click event and can run ATTEDIT, but when I try to pass the position through to the "ATTEDIT Select a block:" it doesn't do anything. But will work when I click on the block again. I thought it was just because I had the units in decimal units rather than architectural. But that doesn't work as well. Here is what I have:
using Autodesk.AutoCAD;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public class DoubleClickProcess
{
// This function gets called when a block reference is double clicked on. It then checks to see if the block reference
// that was double clicked on was double clicked
[CommandMethod("DOUBLECLICK", CommandFlags.UsePickSet)]
public void ContinueDoubleClick()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database database = HostApplicationServices.WorkingDatabase;
Editor ed = doc.Editor;
// Get the PickFirst selection set
PromptSelectionResult acSSPrompt;
acSSPrompt = ed.SelectImplied();
SelectionSet selRes;
// If the prompt status is OK, objects were selected before
// the command was started
if (acSSPrompt.Status == PromptStatus.OK)
{
selRes = acSSPrompt.Value;
Transaction tr = doc.TransactionManager.StartTransaction();
using (tr)
{
// Go through all of the objects that were selected...
ObjectId[] objIds = selRes.GetObjectIds();
foreach (ObjectId objId in objIds)
{
Entity theEnt = (Entity)tr.GetObject(objId, OpenMode.ForRead);
// They must be block references...
if (theEnt.GetType().Name.ToUpper() == "BLOCKREFERENCE")
{
BlockReference bRef = theEnt as BlockReference;
BlockTableRecord btr = null;
btr = tr.GetObject(bRef.DynamicBlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
if (bRef != null)
{
// If it is a specific block then we are interested in it
if (btr.Name.ToString().ToUpper() == "specific")
{
doc.SendStringToExecute("SomeCommand ", true, false, true);
}
else
{
// It's not one we're interested in so do what double clicking would normally do
String objPx = Autodesk.AutoCAD.Runtime.Converter.DistanceToString(bRef.Position.X);
objPx = objPx.Replace(" ", "-");
String objPy = Autodesk.AutoCAD.Runtime.Converter.DistanceToString(bRef.Position.Y);
objPy = objPy.Replace(" ", "-");
String objP = objPx +","+ objPy;
doc.SendStringToExecute("ATTEDIT "+ objP + " ", true, false, true);
}
}
}
theEnt.Dispose();
}
tr.Commit();
}
}
// Clear the PickFirst selection set
ObjectId[] idarrayEmpty = new ObjectId[0];
ed.SetImpliedSelection(idarrayEmpty);
}
}
}
Typing in the architectual position of the mouse works(101'-6-7/8",89'-5-1/2"), but if you type the actual position of the block it doesn't select the block attributes.
I believe it should work with SetImpliedSelection:
SelectionSet selset = SelectionSet.FromObjectIds(new ObjectId[] { bRef.ObjectId });
ed.SetImpliedSelection(selset);
doc.SendStringToExecute("ATTEDIT ", true, false, true);

Creating Large List<T>

I have the following code:
var lstMusicInfo = new List<MediaFile>();
var LocalMusic = Directory.EnumerateFiles(AppSettings.Default.ComputerMusicFolder, "*.*", SearchOption.AllDirectories).AsParallel().ToList<string>();
LocalMusic = (from a in LocalMusic.AsParallel()
where a.EndsWith(".mp3") || a.EndsWith(".wma")
select a).ToList<string>();
var DeviceMusic = adb.SyncMedia(this.dev, AppSettings.Default.ComputerMusicFolder, 1);
Parallel.ForEach(LocalMusic, new Action<string>(item =>
{
try
{
UltraID3 mFile = new UltraID3();
FileInfo fInfo;
mFile.Read(item);
fInfo = new FileInfo(item);
bool onDevice = true;
if (DeviceMusic.Contains(item))
{
onDevice = false;
}
// My Problem starts here
lstMusicInfo.Add(new MediaFile()
{
Title = mFile.Title,
Album = mFile.Album,
Year = mFile.Year.ToString(),
ComDirectory = fInfo.Directory.FullName,
FileFullName = fInfo.FullName,
Artist = mFile.Artist,
OnDevice = onDevice,
PTDevice = false
});
//Ends here.
}
catch (Exception) { }
}));
this.Dispatcher.BeginInvoke(new Action(() =>
{
lstViewMusicFiles.ItemsSource = lstMusicInfo;
blkMusicStatus.Text = "";
doneLoading = true;
}));
#endregion
}));
The first part of the code gives me almost instant result containing:
Address on computer of 5780 files.
Get list of all music files on an android device compare it with those 5780 files and return a list of files found on computer but not on device (in my case it returns a list with 5118 items).
The block of code below is my problem, I am filling data into a class, then adding that class into a List<T>, doing it for 5780 times takes 60 seconds, how can I improve it?
// My Problem starts here
lstMusicInfo.Add(new MediaFile
{
Title = mFile.Title,
Album = mFile.Album,
Year = mFile.Year.ToString(),
ComDirectory = fInfo.Directory.FullName,
FileFullName = fInfo.FullName,
Artist = mFile.Artist,
OnDevice = onDevice,
PTDevice = false
});
//Ends here.
Update:
Here is the profiling result and I see it's obvious why it's slowing down >_>
I suppose I should look for a different library that reads music file information.
One way to avoid loading everything once, up front, would be to lazy load the ID3 information as necessary.
You'd construct your MediaFile instances thus...
new MediaFile(filePath)
...and MediaFile would look something like the following.
internal sealed class MediaFile
{
private readonly Lazy<UltraID3> _lazyFile;
public MediaFile(string filePath)
{
_lazyFile = new Lazy<UltraID3>(() =>
{
var file = new UltraID3();
file.Read(filePath);
return file;
});
}
public string Title
{
get { return _lazyFile.Value.Title; }
}
// ...
}
This is possibly less ideal than loading them as fast as you can in the background, if you do something like MediaFiles.OrderBy(x => x.Title).ToList() and nothing has been lazy loaded then you'll have to wait for every file to load.
Loading them in the background would make them available for use immediately after the background loading has finished. But you might have to concern yourself with not accessing some items until the background loading has finished.
You biggest bottleneck is new FileInfo(item), but you don't need FileInfo just to get the Directory and File names. You can use Path.GetDirectoryName and Path.GetFileName, which are must faster since no I/O is involved.
UltraID3 mFile = new UltraID3();
//FileInfo fInfo;
mFile.Read(item);
//fInfo = new FileInfo(item);
bool onDevice = true;
if (DeviceMusic.Contains(item))
{
onDevice = false;
}
// My Problem starts here
lstMusicInfo.Add(new MediaFile()
{
Title = mFile.Title,
Album = mFile.Album,
Year = mFile.Year.ToString(),
ComDirectory = Path.GetDirectoryName(item), // fInfo.Directory.FullName,
FileFullName = Path.GetFileName(item), //fInfo.FullName,
Artist = mFile.Artist,
OnDevice = onDevice,
PTDevice = false
});
//Ends here.

Background task is skipping schedule, updating every 60 min sometimes

I'm about to loose it soon... I have two apps with working background tasks that are updating the live tile. The data for the live tile is downloaded, parsed and then an image is created dynamically and used as the background for the live tile.
Everything is working just fine for a day or two, but then the updating starts behaving very strange. The first one-two days both live tiles for my apps are updating every 28 minutes like clockwork. But then they start skipping updates. Often app A then updates when app B doesn't update the live tile so that they are not updating at the same time and only once an hour. To put it simple they are way off schedule.
This is really frustrating since I need to be able to rely on the tiles beeing updated every 30 minutes (if I have enough battery, good reception and so on).
I would really appreciate if someone could help me out and maybe take a look at my code to see if there might be something messing up the update interval (like not calling NotifyComplete correctly). I have removed some code and and tried to simplify it. Please ask if you need anything else to understand this.
I have been trying to fix this for the last two months, trying different phones and going throughmy code very carefully.
Your help is more appreciated than you can ever know.
Thanks in advance.
My OnInvoke function:
Timer t = null;
ShellToast toast = new ShellToast();
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(strUrlHBH));
request.Accept = "*/*";
request.AllowAutoRedirect = true;
// disable caching.
request.Headers["Cache-Control"] = "no-cache";
request.Headers["Pragma"] = "no-cache";
t = new Timer(
state =>
{
if (string.Compare(state.ToString(), id, StringComparison.InvariantCultureIgnoreCase) == 0)
{
//logger.Write("Timeout reached for connection [{0}], aborting download.", id);
runNotifyComplete = false;
NotifyComplete();
request.Abort();
t.Dispose();
}
},
id,
timeout,
0);
request.BeginGetResponse(
r =>
{
try
{
if (t != null)
{
t.Dispose();
}
var httpRequest = (HttpWebRequest)r.AsyncState;
var httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(r);
using (var reader = new StreamReader(httpResponse.GetResponseStream()))
{
var response = reader.ReadToEnd();
Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
//Parse the result
if (boolResult) //If we have a result
{
Grid grid = new Grid();
StackPanel sp = new StackPanel();
sp.Height = 173;
sp.Width = 173;
//StreamResourceInfo info = Application.GetResourceStream(new Uri("Pin-to-start2.png", UriKind.Relative));
if ((bool)settings["LiveTileMetro"] == true)
{
// create source bitmap for Image control (image is assumed to be alread 173x173)
/*WriteableBitmap wbmp2 = new WriteableBitmap(1, 1);
wbmp2.SetSource(info.Stream);
Image img = new Image();
img.Source = wbmp2;
// add Image to Grid
grid.Children.Add(img);
strBackBackground = "Pin-to-start2.png";
}
else
{*/
sp.Background = (SolidColorBrush)Application.Current.Resources["PhoneAccentBrush"];
//sp.Background.Opacity = 0.0;
strBackBackground = "";
}
StreamResourceInfo info;
//GC.Collect();
info = Application.GetResourceStream(new Uri("/MyApp;component/images/Icons/livetile/livetile.png", UriKind.Relative));
WriteableBitmap wbmp3 = new WriteableBitmap(1, 1);
try
{
wbmp3.SetSource(info.Stream);
}
catch
{
}
Image img3 = new Image();
img3.Source = wbmp3;
// add Image to Grid
img3.Width = 173;
img3.Height = 173;
img3.Margin = new Thickness { Left = 0, Bottom = 0, Right = 0, Top = 0 };
TextBlock txtTemperature = new TextBlock();
TextBlock txtTemperatureRing = new TextBlock();
txtTemperature.Foreground = new SolidColorBrush(Colors.White);
txtTemperature.Text = strTemp;
txtTemperature.TextAlignment = TextAlignment.Right;
txtTemperatureRing.Style = (Style)Application.Current.Resources["PhoneTextTitle3Style"];
txtTemperatureRing.FontFamily = new FontFamily("Segoe WP Light");
txtTemperatureRing.FontSize = 40;
txtTemperatureRing.Foreground = new SolidColorBrush(Colors.White);
txtTemperatureRing.Text = "°";
txtTemperatureRing.TextAlignment = TextAlignment.Right;
txtTemperature.FontFamily = new FontFamily("Segoe WP Light");
txtTemperature.FontSize = 60;
txtTemperature.Margin = new Thickness { Left = 0, Bottom = 0, Right = 0, Top = -75 };
txtTemperature.Height = 80;
txtTemperature.Width = 145;
txtTemperatureRing.Margin = new Thickness { Left = 128, Bottom = 0, Right = 0, Top = -97 };
txtTemperatureRing.Height = 50;
txtTemperatureRing.Width = 39;
sp.Children.Add(img3);
sp.Children.Add(txtTemperature);
sp.Children.Add(txtTemperatureRing);
//call measure, arrange and updatelayout to prepare for rendering
sp.Measure(new Size(173, 173));
sp.Arrange(new Rect(0, 0, 173, 173));
sp.UpdateLayout();
grid.Children.Add(sp);
WriteableBitmap wbmp = new WriteableBitmap(173, 173);
wbmp.Render(grid, null);
wbmp.Invalidate();
//write image to isolated storage
string sIsoStorePath = #"\Shared\ShellContent\tile.png";
using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
//ensure directory exists
String sDirectory = System.IO.Path.GetDirectoryName(sIsoStorePath);
if (!appStorage.DirectoryExists(sDirectory))
{
appStorage.CreateDirectory(sDirectory);
}
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(sIsoStorePath, System.IO.FileMode.Create, appStorage))
{
wbmp.SaveJpeg(stream, 173, 173, 0, 100);
}
}
/// If application uses both PeriodicTask and ResourceIntensiveTask
//ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains("TileID=2"));
ShellTile TileToFind = ShellTile.ActiveTiles.First();
//test if Tile was created
if (TileToFind != null)
{
StandardTileData NewTileData = new StandardTileData
{
BackgroundImage = new Uri("isostore:Shared/ShellContent/tile.png", UriKind.Absolute),
Title = strTitle,
Count = null,
BackTitle = (string)settings["SelectedCityName"],
BackBackgroundImage = new Uri(strBackBackground, UriKind.Relative),
BackContent = strWind + Environment.NewLine + strPrecipitation
};
//ShellTile.Create(new Uri("/MainPage.xaml?TileID=2", UriKind.Relative), NewTileData);
TileToFind.Update(NewTileData);
}
}
if (runNotifyComplete == true)
{
runNotifyComplete = false;
NotifyComplete();
}
}//If matches.count
}
catch
{
if (runNotifyComplete == true)
{
runNotifyComplete = false;
NotifyComplete();
}
}
finally
{
if (runNotifyComplete == true)
{
runNotifyComplete = false;
NotifyComplete();
}
}
}));
}
if (runNotifyComplete == true)
{
runNotifyComplete = false;
NotifyComplete();
}
}
catch
{
// error handling.
if (runNotifyComplete == true)
{
runNotifyComplete = false;
NotifyComplete();
}
}
finally
{
}
},
request);
}
catch
{
if (runNotifyComplete == true)
{
runNotifyComplete = false;
NotifyComplete();
}
}
finally
{
}
EDIT 1: Here is the code for initializing the background task
MessageBox.Show(MyResources.LiveTileToggleMsgBoxText, "Live tile", MessageBoxButton.OK);
//start background agent
PeriodicTask periodicTask = new PeriodicTask("AppPeriodicAgent0440");
periodicTask.Description = "Periodic task for APP that updates the LiveTile .";
periodicTask.ExpirationTime = System.DateTime.Now.AddDays(14);
// If the agent is already registered with the system,
if (ScheduledActionService.Find(periodicTask.Name) != null)
{
ScheduledActionService.Remove("AppPeriodicAgent0440");
}
try
{
//only can be called when application is running in foreground
ScheduledActionService.Add(periodicTask);
}
catch
{
}
EDIT 2:
This code is run everytime I exit the application in order to keep the background task alive. I put it in OnNavigatedFrom to avoid slowing down the start up of the app
//start background agent
PeriodicTask periodicTask = new PeriodicTask("AppPeriodicAgent0440");
periodicTask.Description = "Periodic task for APP that updates the LiveTile.";
periodicTask.ExpirationTime = System.DateTime.Now.AddDays(14);
// If the agent is already registered with the system,
if (ScheduledActionService.Find(periodicTask.Name) != null)
{
ScheduledActionService.Remove("AppPeriodicAgent0440");
}
//only can be called when application is running in foreground
ScheduledActionService.Add(periodicTask);
If you read the Background Agents overview
http://msdn.microsoft.com/en-us/library/hh202942(v=vs.92).aspx you'll see that it details several scenarios where you schedule won't be followed. For example:
Battery Saver mode is an option that the user can enable on the device
to indicate that battery life should be prioritized. If this mode is
enabled, periodic agents may not run, even if the interval has elapsed
There is no guarantee that the scheduled task will run on the expected schedule. It even has a +/- 10 minute clause in the execution timeschedule.
From your question there is no information about how you're recording other events/tasks that may be happenening on the device at the time you're expecting a schedule to run.
In that you have no logging of errors, timeouts or checking of the LastExitReason of the task there could be all sorts of reasons for the behaviour you're seeing.
If I had to guess where the issue is, based on the information you have provided, I'd presume the problem is with the web request (either the network or the server) and an error in the request causes the UI to not be updated.
There is no way to guarantee that the tile will update on a predictable schedule. If you must absolutely have this updated for your circumstances/requirements then this platform isn't going to be able to provide that guarantee.
If you need multiple tiles to be kept in sync I'd approach this by having all the tiles updated by the same process.
This way, even if there is an inconsistency in the updating of the tiles from a time perspective they'll be in sync with each other.

Categories