【问题标题】:Binding Image to Uri using Caliburn.Micro使用 Caliburn.Micro 将图像绑定到 Uri
【发布时间】:2013-12-15 11:07:22
【问题描述】:

为什么下面的图片没有正确绑定到源?

<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>

背后的代码和视图模型:

namespace SlCaliburnConventionTest
{
    using System;
    using System.Windows.Controls;

    public partial class Sample : UserControl
    {
        public Sample()
        {
            InitializeComponent();

            var viewModel = new SampleViewModel("http://lorempixel.com/300/200/sports/1");
            Caliburn.Micro.ViewModelBinder.Bind(viewModel, this, null);
        }
    }

    public class SampleViewModel
    {
        public SampleViewModel(string url)
        {
            UriProperty = new Uri(url, UriKind.Absolute);
        }

        public Uri UriProperty { get; set; }
    }
}

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

【问题讨论】:

    标签: silverlight caliburn.micro


    【解决方案1】:

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

    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}" />
    

    【讨论】:

    • 谢谢罗伯。我特别想了解如何使 TypeConverters 与 Caliburn.Micro 一起使用。
    【解决方案2】:

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

    <Image Source="http://lorempixel.com/100/100/people" />
    

    然而,编程 API 是这样的:

    class Image {
       ImageSource Source { get; set;}
       DependencyProperty SourceProperty // etc.
    }
    

    字符串是如何变成Uri,再变成ImageSource的?

    答案在于 TypeConverters。

    [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。这是我的 - 主要工作由这一行 public object Convert(...) 执行 - 其他一切都是脚手架:

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

    然后在引导程序中,我们连接新的 IValueConverter:

    protected override void Configure()
    {
        // ...
        ConventionManager.ApplyValueConverter = 
          ValueTypeConverter.ApplyValueConverter;
    }
    

    【讨论】:

    • Caliburn 不允许简单地写&lt;Image Source="{Binding UriProperty}"/&gt; 吗?对我来说看起来容易多了。
    • 请注意,coercion 有不同的含义。你的意思是所谓的类型转换。
    • 你在这两个方面都是对的。谢谢。实际上,我正在研究使用类型转换来显示可由用户替换的图像,因为它似乎是隐藏许多相关复杂性的好方法。
    猜你喜欢
    • 2011-05-01
    • 2015-11-05
    • 1970-01-01
    • 2012-08-07
    • 2014-07-15
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多