Windows Phone View hakt bei asynchronen Aufrufen
Moin ihr,
ich stehe grade etwas auf dem Schlauch und hoffe mir kann jemand helfen.
Kurz zur Beschreibung. Ich arbeite aus langeweile an einem Redmine Manager für Windows Phone (für den ich übrigens bald ein paar Beta-Tester suche. Wer Interesse hat kann sich gerne melden).
Nun habe ich folgendes Problem, das meiner Meinung nach nicht existieren sollte:
Per REST hole ich ein paar Items vom Server ab, deserialisiere sie und speicher sie in einem Caching-System ab. Soweit so gut. Für ein paar Views, z.B. eine Liste der letzten Änderungen, werden erst die gecachten Items an den View geliefert, während im Hintergrund die Collection geupdatet wird. Das ganze passiert asynchron, damit der View nicht blockiert wird.
Und genau da liegt das Problem. Mein View reagiert zwar noch, aber stockt gewaltig bei Interaktion.
Hier der Code, vlt. sieht jemand den Fehler.
Der entsprechende Aufruf aus dem ViewModel
Besten Dank
Moin ihr,
ich stehe grade etwas auf dem Schlauch und hoffe mir kann jemand helfen.
Kurz zur Beschreibung. Ich arbeite aus langeweile an einem Redmine Manager für Windows Phone (für den ich übrigens bald ein paar Beta-Tester suche. Wer Interesse hat kann sich gerne melden).
Nun habe ich folgendes Problem, das meiner Meinung nach nicht existieren sollte:
Per REST hole ich ein paar Items vom Server ab, deserialisiere sie und speicher sie in einem Caching-System ab. Soweit so gut. Für ein paar Views, z.B. eine Liste der letzten Änderungen, werden erst die gecachten Items an den View geliefert, während im Hintergrund die Collection geupdatet wird. Das ganze passiert asynchron, damit der View nicht blockiert wird.
Und genau da liegt das Problem. Mein View reagiert zwar noch, aber stockt gewaltig bei Interaktion.
Hier der Code, vlt. sieht jemand den Fehler.
Code:
public static async Task<T> Get<T>( int id, Func<Task<T>> updateData = null, bool forceUpdate = false )
{
ValidateConnection();
string json;
CachedEntry<T> entry;
string key = string.Format( "{0}-{1}-{2}", ViewModelBase.CurrentConnection.Id, Prefix[typeof (T)], id );
if ( !forceUpdate && IsolatedStorageSettings.ApplicationSettings.TryGetValue( key, out json ) )
{
entry = SerializationManager.Deserialize<CachedEntry<T>>( json );
if ( entry.IsValid || updateData == null )
{
return entry.Data;
}
}
if ( updateData == null ) return default(T);
T newData = await updateData.Invoke();
entry = new CachedEntry<T> { Data = newData, UpdatedOn = DateTime.Now };
json = SerializationManager.Serialize( entry );
IsolatedStorageSettings.ApplicationSettings[key] = json;
IsolatedStorageSettings.ApplicationSettings.Save();
return newData;
}
public static async Task SetDelayed<T>( int id, Func<Task<T>> updateData, Action<T> updateView )
{
T cached = await Get<T>( id );
InvokeThreadSafe( updateView, cached );
T updated = await Get( id, updateData, true );
InvokeThreadSafe( updateView, updated );
}
private static void ValidateConnection()
{
if ( ViewModelBase.CurrentConnection == null )
throw new InvalidOperationException();
}
private static void InvokeThreadSafe<T>( Action<T> action, T input )
{
var dispatcher = Deployment.Current.Dispatcher;
if ( dispatcher.CheckAccess() )
{
action.Invoke( input );
}
else
{
dispatcher.BeginInvoke( () => action.Invoke( input ) );
}
}
Der entsprechende Aufruf aus dem ViewModel
Code:
public ObservableCollection<Issue> IssueActivity { get; private set; }
private async Task InitActivity()
{
IsLoading = true;
Func<Task<IList<Issue>>> fetchIssues = async () =>
{
try
{
RedmineManager manager = CurrentConnection.GetManager();
var @params = new Dictionary<string, string>
{
{ "sort", "updated_on:desc" },
{ "limit", "10" },
{ "status_id", "*" }
};
RedmineMultiResponse<Issue> response = await manager.GetIssues( @params );
return response.ResponseDataCollection;
}
catch ( Exception ex )
{
// ToDo.
return new List<Issue>();
}
};
Action<IList<Issue>> updateView = list =>
{
// ToDo.
if ( IssueActivity.Count > 0 && list.Count > 0 )
IssueActivity.Clear();
foreach ( var issue in list )
IssueActivity.Add( issue );
};
await CacheManager.SetDelayed( Constants.OverviewPageActivityId, fetchIssues, updateView );
IsLoading = false;
}
Besten Dank
Zuletzt bearbeitet: