Non valide cross-thread problème d'accès à la
J'ai deux classes ViewModel : PersonViewModel et PersonSearchListViewModel. L'un des domaines PersonViewModel met en place est une image de profil qui est téléchargé via WCF(mis en cache localement dans le stockage isolé). Le PersonSearchListViewModel est une classe de conteneur qui contient une liste de Personnes. Depuis le chargement des images est relativement lourd, PersonSearchListViewModel charge uniquement les images pour le courant, la suivante et page précédente (les résultats sont paginées sur l'INTERFACE utilisateur)...pour améliorer encore la charge des images que j'ai mis le chargement des images sur un autre thread. Cependant le multi-threading approche des causes de la croix-thread problèmes d'accès.
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();
}
}
}
Comment voulez-vous traiter les données en classe ViewModel en multi-thread manière ? Je sais que vous devez utiliser le dispatcher sur l'INTERFACE utilisateur de mise à jour. Comment voulez-vous mettre à jour ViewModel qui est lié à l'INTERFACE utilisateur ?
** EDIT **
Il y a encore une erreur bizarre qui se passe. Dans le code ci-dessous :
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);
}
}
- Je obtenir un cross-thread d'erreur lorsque vous essayez de créer un nouvel objet BitmapImage dans le thread d'arrière-plan. Pourquoi ne puis-je pas créer un nouvel objet BitmapImage sur un thread d'arrière-plan ?
Vous devez vous connecter pour publier un commentaire.
Afin de mettre à jour une DependencyProperty dans un ViewModel, utiliser le même répartiteur vous pouvez utiliser pour accéder à d'autres UIElement:
Aussi, BitmapImages être instancié sur le thread de l'INTERFACE utilisateur. C'est parce qu'il utilise DependencyProperties, qui ne peut être utilisé sur le thread d'INTERFACE utilisateur. J'ai essayé de l'instanciation BitmapImages sur des threads séparés et il ne fonctionne tout simplement pas. Vous pouvez essayer d'utiliser d'autres moyens pour stocker des images dans la mémoire. Par exemple, lorsque vous téléchargez l'image, de le stocker dans un MemoryStream. Puis un BitmapImage sur le thread d'INTERFACE utilisateur peut définir sa source à la MemoryStream.
Vous pouvez essayer de l'instanciation de la BitmapImages sur le thread d'INTERFACE utilisateur et ensuite faire tout le reste avec BitmapImage sur un autre thread... mais qui serait poilu et je ne suis même pas sûr que ça marcherait. Voici un exemple:
Je crois que vous avez de la croix-threading problème avec le thread de l'INTERFACE utilisateur.
D'édition de l'objet lié peut forcer une mise à jour de l'INTERFACE utilisateur sur le thread de travail, qui ne peut pas réussir. Vous aurez probablement besoin de faire de la InvokeRequired/Invoke hokey-pokey à chaque mise à jour de la classe liée.
Tu as dit que tu le savais déjà, mais pour référence:
MSDN thread-safe appels de l'INTERFACE utilisateur
Il peut être réalisé avec WriteableBitmap.
Mais Vous avez à construire WriteableBitmap dans le Thread de l'INTERFACE utilisateur, puis le chargement peut être effectué dans l'autre thread.
Voir plus explanaition sur ce post de blog