2013-12-15 3 views
1

Почему следующее изображение не связывается с источником правильно?Связывание изображения с Uri с использованием 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/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?

ответ

2

Управление изображениями демонстрирует интересное свойство XAML, известное как преобразование . Например, XAML апите для изображений выглядеть следующим образом:

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

Однако программирование API выглядит так:

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

Как строка заводится в Ури, а затем превратилась в 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; 
} 
+1

ли Caliburn не позволяют просто написать ''? Мне намного легче. – Clemens

+1

И обратите внимание, что * принуждение * означает что-то другое. То, что вы имеете в виду, называется преобразованием типов. – Clemens

+0

Вы правы по обоим пунктам. Благодарю. Я действительно изучал использование преобразования типов для отображения изображений, которые могут быть заменены пользователем, так как это казалось хорошим способом скрыть большую часть связанной с этим сложности. –

2

Я использую строку в качестве свойство подложки и переплетные работы для меня:

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

Спасибо, Роб. Я специально пытался понять, как заставить TypeConverters работать с Caliburn.Micro. –

Смежные вопросы