Ho due classi ViewModel: PersonViewModel e PersonSearchListViewModel. Uno dei campi di implementazione di PersonViewModel è un'immagine del profilo che viene scaricata tramite WCF (memorizzata nella cache locale in una memoria isolata). PersonSearchListViewModel è una classe contenitore che contiene un elenco di Persone. Dal momento che il caricamento delle immagini è relativamente pesante, PersonSearchListViewModel carica solo le immagini per la pagina corrente, successiva e precedente (i risultati sono paginati sull'interfaccia utente) ... per migliorare ulteriormente il carico di immagini metto il carico di immagini su un altro thread. Tuttavia, l'approccio multi-threading causa problemi di accesso cross-thread.Problema di accesso incrociato non valido
PersonViewModel:
public void RetrieveProfileImage()
{
Image profileImage = MemorialDataModel.GetImagePerPerson(Person);
if (profileImage != null)
{
MemorialDataModel.ImageManager imgManager = new MemorialDataModel.ImageManager();
imgManager.GetBitmap(profileImage, LoadProfileBitmap);
}
}
private void LoadProfileBitmap(BitmapImage bi)
{
ProfileImage = bi;
// update
IsProfileImageLoaded = true;
}
private BitmapImage profileImage;
public BitmapImage ProfileImage
{
get
{
return profileImage;
}
set
{
profileImage = value;
RaisePropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("ProfileImage"));
}
}
PersonSearchListViewModel:
private void LoadImages()
{
// load new images
Thread loadImagesThread = new Thread(new ThreadStart(LoadImagesProcess));
loadImagesThread.Start();
//LoadImagesProcess(); If executed on the same thread everything works fine
}
private void LoadImagesProcess()
{
int skipRecords = (PageIndex * PageSize);
int returnRecords;
if (skipRecords != 0)
{
returnRecords = 3 * PageSize; // page before, cur page and next page
}
else
{
returnRecords = 2 * PageSize; // cur page and next page
}
var persons = this.persons.Skip(skipRecords).Take(returnRecords);
// load images
foreach (PersonViewModel pvm in persons)
{
if (!pvm.IsProfileImageLoaded)
{
pvm.RetrieveProfileImage();
}
}
}
come elaborare i dati in classe ViewModel in maniera multi-threaded? So che devi utilizzare il dispatcher sull'interfaccia utente per l'aggiornamento. Come aggiorni ViewModel associato a UI?
** EDIT **
C'è anche un altro errore di strano accade. Nel codice riportato di seguito:
public void GetBitmap(int imageID, Action<BitmapImage> callback)
{
// Get from server
bitmapCallback = callback;
memorialFileServiceClient.GetImageCompleted += new EventHandler<GetImageCompletedEventArgs>(OnGetBitmapHandler);
memorialFileServiceClient.GetImageAsync(imageID);
}
public void OnGetBitmapHandler(object sender, GetImageCompletedEventArgs imageArgs)
{
if (!imageArgs.Cancelled)
{
// I get cross-thread error right here
System.Windows.Media.Imaging.BitmapImage bi = new BitmapImage();
ConvertToBitmapFromBuffer(bi, imageArgs.Result.Image);
// call call back
bitmapCallback.Invoke(bi);
}
}
Viene visualizzato un errore cross-thread durante il tentativo di creare un nuovo oggetto BitmapImage nel thread in background. Perché non riesco a creare un nuovo oggetto BitmapImage su un thread in background?
Grande, che è esattamente quello che stavo cercando. Sono andato con byte [] come mezzo di archiviazione. – Ender
anche questo mi ha aiutato quando ho dovuto generare un evento PropertyChanged per più proprietà dopo che ne è stato impostato uno. –
Non ho realizzato un BitmapImage necessario per il thread dell'interfaccia utente. Avrei davvero dovuto pensarci, dal momento che una DependencyProperty sarebbe stata un problema altrimenti. :: facepalm :: – Paul