Reputation: 2861
I've got an interesting issue with an app for Windows Phone 7. Right now, I'm sending out some two dozen or so requests for small (a few KB) xml files to keep rapidly changing information (bus locations to be exact). I have a Timer ticking off every 10 sec to send out the requests asyncronously.
The data retreived is handled with an asynchronous callback to verify the request came back with a file, and stores the file into IsolatedStorage. When the data is needed (by the View-Model of the UI), the file is read from IsolatedStorage, parsed into internal objects (basically a GeoCoordinate and some strings) and used.
1) I'm running into the limitations of the phone's CPU here, just a bit. If I parse all the bus data to determine which bus routes are active on the UI thread, the thread noticably slows down. I moved the work into a bakground worker like this:
public class RunningWorkerHelper
{
public BusRouteIdModel Route { get; set; }
public Visibility Visible { get; set; }
}
public class RunningWorker
{
BackgroundWorker bw;
Queue<BusRouteIdModel> workQueue;
public RunningWorker()
{
bw = new BackgroundWorker();
workQueue = new Queue<BusRouteIdModel>();
bw.DoWork += CheckIfRunning;
bw.RunWorkerCompleted += CheckRunningCompleted;
}
public void QueueWorkItem(BusRouteIdModel route)
{
workQueue.Enqueue(route);
StartWorkItem();
}
void StartWorkItem()
{
if (!bw.IsBusy && workQueue.Count > 0)
bw.RunWorkerAsync(workQueue.Dequeue());
}
void CheckIfRunning(object sender, DoWorkEventArgs args)
{
BusRouteDataService server= BusRouteDataService.Current;
var route = (BusRouteIdModel)args.Argument;
if (route == null) return;
var vehicleFile = server.GetBusVehiclesFile(route);
var vehiclesOnRoute = RouteDataParser.ExtractBusVehicles(vehicleFile);
var helper = new RunningWorkerHelper { Route = route };
if (vehiclesOnRoute.Count > 0)
{
helper.Visible = Visibility.Visible;
}
else
{
helper.Visible = Visibility.Collapsed;
}
args.Result = helper;
}
void CheckRunningCompleted(object sender, RunWorkerCompletedEventArgs args)
{
var helper = (RunningWorkerHelper)args.Result;
if (helper != null)
helper.Route.IsRunning = helper.Visible;
StartWorkItem();
}
}
here's the BusRouteIdModel (for reference)
public class BusRouteIdModel : BusRouteId, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
Visibility _isRunning;
/// <summary>
/// True when there is a bus active on this route
/// </summary>
public Visibility IsRunning
{
get { return _isRunning; }
set
{
if (value == _isRunning) return;
_isRunning = value;
OnPropertyChanged(new PropertyChangedEventArgs("IsRunnning"));
}
}
/// <summary>
/// True while path data for the route isn't available yet
/// </summary>
Visibility _isLoading;
public Visibility IsLoading
{
get { return _isLoading; }
set
{
if (value == _isLoading) return;
_isLoading = value;
OnPropertyChanged(new PropertyChangedEventArgs("IsLoading"));
}
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
if (PropertyChanged != null)
PropertyChanged(this, args);
}
}
public class BusRouteId
{
public String Uid { get; set; }
public String Name { get; set; }
}
This is data bound to a listbox element on the page (I'm using the MVVM Light Toolkit):
public const string RouteIdsPropertyName = "RouteIds";
private ObservableCollection<BusRouteIdModel> _routeIds = null;
public ObservableCollection<BusRouteIdModel> RouteIds
{
get { return _routeIds; }
private set
{
if (_routeIds == value) return;
var oldValue = _routeIds;
_routeIds = value;
RaisePropertyChanged(RouteIdsPropertyName);
}
}
And I call my worker like this (the args.Uid id's the bus route that got new data):
foreach (var route in RouteIds)
if (route.Uid == args.Uid)
runningWorker.QueueWorkItem(route);
2) Mysteriously, the IsRunning change isn't reflected in the UI. What did I miss?
3) How can I generalize this Queue + BackgroundWorker to handle other tasks? (I would use the Task Pool Library, but Silverlight does not have it.) I want to have a single worker so that the UI thread doesn't get starved on the map page.
Upvotes: 1
Views: 297
Reputation: 66882
1) Not a question?
2) IsRunning in the UI isn't updating because of a typo:
OnPropertyChanged(new PropertyChangedEventArgs("IsRunnning"))
Too many n's
3) For threading like this, try ThreadPool
- see http://wildermuth.com/2011/01/11/Architecting_WP7_-_Part_9_of_10_Threading
Upvotes: 3