Silverlight 使用Caliburn.Micro将图像绑定到Uri

Silverlight 使用Caliburn.Micro将图像绑定到Uri,silverlight,caliburn.micro,Silverlight,Caliburn.micro,为什么下面的图像不能正确绑定到源 <UserControl x:Class="SlCaliburnConventionTest.Sample" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expr

为什么下面的图像不能正确绑定到源

<UserControl x:Class="SlCaliburnConventionTest.Sample"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <Image x:Name="UriProperty" />
    </Grid>
</UserControl>

我深入研究了Caliburn.Micro源代码,发现它在应用约定时没有使用TypeDescriptor。问题是:我们如何说服Caliburn.Micro将URI转换为ImageSource?

图像控件演示了XAML的一个有趣特性,即类型转换。例如,图像的XAML api如下所示:

<Image Source="http://lorempixel.com/100/100/people" />
class Image {
   ImageSource Source { get; set;}
   DependencyProperty SourceProperty // etc.
}
字符串是如何转换成Uri,然后转换成ImageSource的

答案在于类型转换器

[TypeConverter(typeof(ImageSourceConverter))]
public class ImageSource {}
当我们以编程方式创建到Uri的绑定时,上面的魔法不会发生。结果是没有显示任何图片

// No picture is shown.
BindingOperations.SetBinding(myImage, 
  Image.SourceProperty, new Binding("MyUri"));
同样,我们不能这样做:

// compile time error
myImage.Source = new Uri("http://...")
相反,正确的方法是从ImageSource的自定义属性中获取类型转换器,并将其转换为IValueConverter。这是我的-主要工作由这一行
公共对象转换(…)
执行-其他一切都是脚手架:

namespace Caliburn.Micro
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;

    public class ValueTypeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var result = TypeDescriptor.GetConverter(targetType).ConvertFrom(value);
            return result;
        }

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

        /// <summary>
        /// Binding Image.Source to an Uri typically fails.
        /// Calling the following during application bootstrap will set this up properly.
        ///    ConventionManager.ApplyValueConverter = ValueTypeConverter.ApplyValueConverter;
        /// </summary>
        /// <param name="binding"></param>
        /// <param name="bindableProperty"></param>
        /// <param name="info"></param>
        public static void ApplyValueConverter(Binding binding, DependencyProperty bindableProperty, PropertyInfo info)
        {
            if (bindableProperty == UIElement.VisibilityProperty && typeof(bool).IsAssignableFrom(info.PropertyType))
                binding.Converter = ConventionManager.BooleanToVisibilityConverter;

            else if (bindableProperty == Image.SourceProperty && typeof(Uri).IsAssignableFrom(info.PropertyType))
                binding.Converter = new ValueTypeConverter();
            else
            {
                foreach (var item in _Conventions)
                {
                    if (bindableProperty == item.Item1 && item.Item2.IsAssignableFrom(info.PropertyType))
                        binding.Converter = new ValueTypeConverter();
                }
            }
        }

        /// <summary>
        /// If there is a TypeConverter that can convert a <paramref name="SourceType"/>
        /// to the type on <paramref name="bindableProperty"/>, then this has to
        /// be manually registered with Caliburn.Micro as Silverlight is unable to 
        /// extract sufficient TypeConverter information from a dependency property
        /// on its own.
        /// </summary>
        /// <example>
        /// ValueTypeConverter.AddTypeConverter&lt;ImageSource&gt;(Image.SourceProperty);
        /// </example>
        /// <typeparam name="SourceType"></typeparam>
        /// <param name="bindableProperty"></param>
        public static void AddTypeConverter<SourceType>(DependencyProperty bindableProperty)
        {
            _Conventions.Add(Tuple.Create<DependencyProperty, Type>(bindableProperty, typeof(SourceType)));
        }

        private static IList<Tuple<DependencyProperty, Type>> _Conventions = new List<Tuple<DependencyProperty, Type>>();
    }
}

图像控件演示了XAML的一个有趣属性,即类型转换。例如,图像的XAML api如下所示:

<Image Source="http://lorempixel.com/100/100/people" />
class Image {
   ImageSource Source { get; set;}
   DependencyProperty SourceProperty // etc.
}
字符串是如何转换成Uri,然后转换成ImageSource的

答案在于类型转换器

[TypeConverter(typeof(ImageSourceConverter))]
public class ImageSource {}
当我们以编程方式创建到Uri的绑定时,上面的魔法不会发生。结果是没有显示任何图片

// No picture is shown.
BindingOperations.SetBinding(myImage, 
  Image.SourceProperty, new Binding("MyUri"));
同样,我们不能这样做:

// compile time error
myImage.Source = new Uri("http://...")
相反,正确的方法是从ImageSource的自定义属性中获取类型转换器,并将其转换为IValueConverter。这是我的-主要工作由这一行
公共对象转换(…)
执行-其他一切都是脚手架:

namespace Caliburn.Micro
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;

    public class ValueTypeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var result = TypeDescriptor.GetConverter(targetType).ConvertFrom(value);
            return result;
        }

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

        /// <summary>
        /// Binding Image.Source to an Uri typically fails.
        /// Calling the following during application bootstrap will set this up properly.
        ///    ConventionManager.ApplyValueConverter = ValueTypeConverter.ApplyValueConverter;
        /// </summary>
        /// <param name="binding"></param>
        /// <param name="bindableProperty"></param>
        /// <param name="info"></param>
        public static void ApplyValueConverter(Binding binding, DependencyProperty bindableProperty, PropertyInfo info)
        {
            if (bindableProperty == UIElement.VisibilityProperty && typeof(bool).IsAssignableFrom(info.PropertyType))
                binding.Converter = ConventionManager.BooleanToVisibilityConverter;

            else if (bindableProperty == Image.SourceProperty && typeof(Uri).IsAssignableFrom(info.PropertyType))
                binding.Converter = new ValueTypeConverter();
            else
            {
                foreach (var item in _Conventions)
                {
                    if (bindableProperty == item.Item1 && item.Item2.IsAssignableFrom(info.PropertyType))
                        binding.Converter = new ValueTypeConverter();
                }
            }
        }

        /// <summary>
        /// If there is a TypeConverter that can convert a <paramref name="SourceType"/>
        /// to the type on <paramref name="bindableProperty"/>, then this has to
        /// be manually registered with Caliburn.Micro as Silverlight is unable to 
        /// extract sufficient TypeConverter information from a dependency property
        /// on its own.
        /// </summary>
        /// <example>
        /// ValueTypeConverter.AddTypeConverter&lt;ImageSource&gt;(Image.SourceProperty);
        /// </example>
        /// <typeparam name="SourceType"></typeparam>
        /// <param name="bindableProperty"></param>
        public static void AddTypeConverter<SourceType>(DependencyProperty bindableProperty)
        {
            _Conventions.Add(Tuple.Create<DependencyProperty, Type>(bindableProperty, typeof(SourceType)));
        }

        private static IList<Tuple<DependencyProperty, Type>> _Conventions = new List<Tuple<DependencyProperty, Type>>();
    }
}

我使用字符串作为支持属性,绑定适用于我:

public class TestViewModel : ViewModelBase
{
    public TestViewModel()
    {
        ImageUrl = "http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png";
    }

    public string ImageUrl { get; set; }
}

<Image Source="{Binding ImageUrl}" />
公共类TestViewModel:ViewModelBase
{
公共TestViewModel()
{
ImageUrl=”http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png";
}
公共字符串ImageUrl{get;set;}
}

我使用字符串作为支持属性,绑定对我有效:

public class TestViewModel : ViewModelBase
{
    public TestViewModel()
    {
        ImageUrl = "http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png";
    }

    public string ImageUrl { get; set; }
}

<Image Source="{Binding ImageUrl}" />
公共类TestViewModel:ViewModelBase
{
公共TestViewModel()
{
ImageUrl=”http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png";
}
公共字符串ImageUrl{get;set;}
}

Caliburn不允许只写
?在我看来要容易得多。请注意,强迫意味着不同的东西。你的意思是所谓的类型转换。在这两方面你都是对的。谢谢实际上,我正在研究使用类型转换来显示用户可以替换的图像,因为这似乎是隐藏大部分相关复杂性的好方法。Caliburn不允许简单地编写
?在我看来要容易得多。请注意,强迫意味着不同的东西。你的意思是所谓的类型转换。在这两方面你都是对的。谢谢实际上,我正在研究如何使用类型转换来显示用户可以替换的图像,因为这似乎是一种很好的方法来隐藏与此相关的复杂性。谢谢Rob。我特别想了解如何使用Caliburn.Micro使类型转换器工作。谢谢Rob。我特别想了解如何使类型转换器与Caliburn.Micro一起工作。