2017-10-17 18 views
1

J'ai un contrôle d'image WPF dont la propriété source est liée à une propriété qui renvoie une image. Puis j'ai un convertisseur qui prend l'image liée à la propriété source et la convertit en bitmapImage. Lorsque le téléchargement de bitmapimage est terminé, je voudrais exécuter une méthode dans mon modèle de vue, donc je me suis abonné à l'événement DownloadCompleted dans BitmapImage. Alors, comment puis-je appeler la méthode dans le modèle de vue du convertisseur? cela romprait-il les principes du MVVM?WPF MVVM: Appel d'une méthode dans un modèle de vue à partir d'un convertisseur

Converter:

public class ImgToSrcConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, 
      System.Globalization.CultureInfo culture) 
    { 
     Image image = value as Image; 
     if (image != null) 
     { 
      MemoryStream ms = new MemoryStream(); 
      image.Save(ms, image.RawFormat); 
      ms.Seek(0, SeekOrigin.Begin); 
      BitmapImage bi = new BitmapImage(); 
      bi.BeginInit(); 
      bi.StreamSource = ms; 
      bi.EndInit(); 

      bi.DownloadCompleted += new EventHandler(bi_DownloadCompleted); 

      return bi; 
     } 
     return null; 
    } 

    public object ConvertBack(object value, Type targetType, 
     object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 

    private void bi_DownloadCompleted(object sender, EventArgs e) 
    { 
     // Call my method in view model 
    } 
} 
+0

S'il est important pour votre application d'avoir 'BitmapImage', alors la propriété' ImageSrc' dans le modèle de vue doit être de type 'BitmapImage' et vous n'aurez pas besoin de convertisseur – ASh

+0

Je ne suis pas sûre de comprendre ce que vous ' Re essayant de réaliser? Pourriez-vous élaborer un peu sur ce que vous essayez exactement de faire? Que voulez-vous dire par "téléchargement"? Que ferez-vous lorsque ce "téléchargement" sera terminé? –

Répondre

3

Vous pouvez utiliser un multi-convertisseur qui accepte plusieurs valeurs:

public class ImgToSrcConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     Image image = values[0] as Image; 
     if (image != null) 
     { 
      MemoryStream ms = new MemoryStream(); 
      image.Save(ms, image.RawFormat); 
      ms.Seek(0, SeekOrigin.Begin); 
      BitmapImage bi = new BitmapImage(); 
      bi.BeginInit(); 
      bi.StreamSource = ms; 
      bi.EndInit(); 

      ViewModel vm = values[1] as ViewModel; 
      bi.DownloadCompleted += (s, e) => 
      { 
       vm.Method(); 
      }; 

      return bi; 
     } 
     return null; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Utilisation:

<Image Grid.Row="0"> 
    <Image.Source> 
     <MultiBinding NotifyOnTargetUpdated="True" Converter="{StaticResource imgToSrcConverter}"> 
      <Binding Path="ImageSrc" /> 
      <Binding Path="." /> 
     </MultiBinding> 
    </Image.Source> 
</Image> 

Et non, cela ne casse pas le modèle MVVM tant que votre logique d'application testable reste dans le modèle de vue.

+0

En utilisant votre solution, lorsque la propriété "ImageSrc" dans le modèle de vue est modifiée, le convertisseur est atteint, mais maintenant l'événement DownloadCompleted n'est jamais déclenché. Pourquoi? Peut-être parce que l'objet bi est détruit une fois que bi est retourné? – user1624552

+0

J'ai défini le gestionnaire d'événements comme une méthode anonyme dans mon exemple de code. En plus de ça, je n'ai rien changé. Avez-vous mis un point d'arrêt dans la méthode anonyme? Si l'événement a été soulevé auparavant, il sera toujours levé. – mm8

+0

Oui, je mets un point d'arrêt dans la ligne vm.Method(); dans l'événement DownloadCompleted anonyme. La méthode du convertisseur est exécutée mais l'événement n'est jamais déclenché. – user1624552

1

Qu'est-ce que vous pouvez faire est passer le DataContext directement au convertisseur, puis accéder à la propriété applicable/méthode à partir de là.

l'image mise à jour XAML à:

<Image Grid.Row="0" 
     Source="{Binding Path=DataContext, 
         RelativeSource={RelativeSource Self}, 
         NotifyOnTargetUpdated=True, 
         Converter={StaticResource imgToSrcConverter}}" /> 

Ensuite, maintenez une référence à votre ViewModel et appeler en conséquence:

public class ImgToSrcConverter : IValueConverter 
{ 
    private MyViewModel _dataContext; 

    public object Convert(object value, Type targetType, object parameter, 
      System.Globalization.CultureInfo culture) 
    { 
     var dataContext = value as MyViewModel; 
     if (dataContext != null) 
     { 
      _dataContext = dataContext; 

      var image = dataContext.ImageSrc as Image; 
      if (image != null) 
      { 
       MemoryStream ms = new MemoryStream(); 
       image.Save(ms, image.RawFormat); 
       ms.Seek(0, SeekOrigin.Begin); 
       BitmapImage bi = new BitmapImage(); 
       bi.BeginInit(); 
       bi.StreamSource = ms; 
       bi.EndInit(); 

       bi.DownloadCompleted += new EventHandler(bi_DownloadCompleted); 

       return bi; 
      } 
     } 
     return null; 
    } 

    public object ConvertBack(object value, Type targetType, 
     object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 

    private void bi_DownloadCompleted(object sender, EventArgs e) 
    { 
     _dataContext?.MyMethod(); 
    } 
}   

Remarque, que je pense que c'est un peu de code- odeur pour MVVM, typiquement, vous ne voudriez jamais que votre ViewModel soit accessible via le convertisseur. Pour moi, il semble qu'une partie de cette logique peut être chargée/maintenue dans le ViewModel lui-même plutôt que de s'appuyer sur un convertisseur.

+0

En utilisant ceci, le convertisseur n'est pas appelé. – user1624552

+0

@ user1624552 Vous avez créé la ressource pour le convertisseur avec une clé de 'imgToSrcConverter' dans un endroit accessible à la liaison? –

+0

@BradleyUffner Oui, je l'ai créé au début de la fenêtre dans la section Window.Resources. Toujours sous les ressources de la fenêtre, tout le contenu se trouve dans une grille principale dans laquelle j'associe le contexte de données comme suit: . Peut-être que cela affecte et c'est la cause pourquoi le convertisseur n'est pas appelé? – user1624552