2017-10-17 13 views
1

私は、そのsourceプロパティがイメージを返すプロパティにバインドされたWPFイメージコントロールを持っています。WPF MVVM:コンバーターからビューモデルのメソッドを呼び出す

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

次に、ソースプロパティにバインドされたイメージを取得し、それをbitmapImageに変換するコンバータがあります。 bitmapimageのダウンロードが終了したら、ビューモデルでメソッドを実行したいので、BitmapImageでDownloadCompletedイベントを購読しています。だから私はどのようにコンバータからのビューモデルのメソッドを呼び出すことができますか?それはMVVMの原則を破るだろうか?

コンバータ

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

あなたのアプリが 'BitmapImage'を持っていることが重要な場合は、ビューモデルの' ImageSrc'プロパティは 'BitmapImage'型でなければなりません。コンバータは必要ありません – ASh

+0

私は、再達成しようとしている?ちょうどあなたがやろうとしていることについて少し詳しく説明できますか? 「ダウンロード」とはどういう意味ですか?この「ダウンロード」が完了したら、あなたは何をしていますか? –

答えて

3

あなたはいくつかの値を受け入れるマルチコンバータを使用することができます。

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(); 
    } 
} 

用途:

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

そして、いや、これは限りMVVMパターンを破壊しませんテスト可能なアプリケーションロジックはビューモデルにとどまります。

+0

ソリューションを使用すると、ビューモデルのプロパティ "ImageSrc"が変更されたときにコンバーターに到達しましたが、今度はDownloadCompletedイベントは発生しません。どうして? Biが返されると、Biオブジェクトが破壊される可能性がありますか? – user1624552

+0

サンプルコードでは、イベントハンドラを匿名メソッドとして定義しました。この他に、私は何も変えなかった。匿名メソッドにブレークポイントを設定しましたか?以前にイベントが発生した場合は、引き上げられます。 – mm8

+0

はい、vm.Method()行にブレークポイントを設定します。匿名のDownloadCompletedイベント内。コンバータメソッドは実行されますが、イベントは発生しません。 – user1624552

1

何ができるかは、コンバータに直接DataContextを渡し、そこから該当するプロパティ/メソッドにアクセスしています。

更新画像XAMLに:私は、これはコード - ビットであると感じていること、

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(); 
    } 
}   

を:次に

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

、あなたのViewModelへの参照を保持し、それに応じて呼び出しますMVVMの臭いは、典型的にはあなたのViewModelがコンバータを介してアクセスできるようにすることは決してありません。私にとって、このロジックのいくつかは、コンバータに依存するのではなく、ViewModel自体の中でロード/維持できるようです。

+0

これを使用すると、コンバータは呼び出されていません。 – user1624552

+0

@ user1624552あなたはバインディングにアクセスできる場所に 'imgToSrcConverter'というキーを持つコンバータ用のリソースを作成しましたか? –

+0

@BradleyUffnerはい、Window.Resourcesセクション内のウィンドウの最初に作成しました。また、ウィンドウリソースの下にあるすべてのコンテンツは、以下のようにdatacontextを関連付けるメイングリッド内にあります。たぶんこれが影響していて、コンバータが呼び出されないのはなぜですか? – user1624552

0

あなたがコンバータにあなたのイメージとのDataContext(vievmodel)を得ることができるので、IMultiValueConverterを使用してのアプローチをtheresの... WPF: MultiBinding and IMultiValueConverter

もう一つの方法は、EventAggregator/MessageBusなり、その後、あなたのViewModelにメッセージを送ることができます。 ..?多くの人がMessageBusを反パターンと見なすことができると主張します。 Roll Your Own Simple Message Bus/Event Aggregator

関連する問題