WPF MVVM:从转换器调用视图模型中的方法

时间:2017-10-17 23:46:50

标签: c# wpf mvvm

我有一个WPF图像控件,它的source属性绑定到一个返回图像的属性。

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

然后我有一个转换器,它将图像绑定到source属性并将其转换为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
    }
}

3 个答案:

答案 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模式。

答案 1 :(得分:1)

您可以做的是将DataContext直接传递给转换器,然后从那里访问适用的属性/方法。

将图片xaml更新为:

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

然后,保持对ViewModel的引用,并相应地调用:

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

注意,我觉得这对于MVVM来说有点代码味道,通常情况下,您永远不会希望通过转换器访问ViewModel。对我来说,似乎有些逻辑可以在ViewModel本身内加载/维护,而不是依赖于转换器。

答案 2 :(得分:0)

Theres是一种使用IMultiValueConverter的方法,因此您可以将图像和datacontext(vievmodel)转换为转换器... WPF: MultiBinding and IMultiValueConverter

另一种方法可能是EventAggregator / MessageBus,然后向您的ViewModel发送消息......?尽管许多人认为MessageBus可以被视为反模式。 Roll Your Own Simple Message Bus / Event Aggregator