2

我正在为 Metro UI 开发一个 ImagePicker 用户控件。它的原理很简单:它显示一个图像,当点击图像时,会打开一个文件对话框,允许更改当前图像。为此,用户控件只需公开包装图像绑定到的 ImageSource 属性。

<local:ImagePicker Source="{Binding PictureUri, Mode=TwoWay}"/>

在启动时,绑定工作正常,并显示来自我的视图模型提供的 PictureUri 属性的图片。问题是,当我点击图像并选择一个新图像时,会显示新图像,但尽管使用了 TwoWay 绑定模式,但我的视图模型中的绑定值并未更新。我相信这个问题来自我的用户控制代码,但我不明白为什么当它实际传播到包装图像时该值没有传播到视图模型......

所以这里是 XAML 部分。

<UserControl x:Name="ImagePickerUserControl"
    x:Class="ImageUserControl.ImagePicker"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid x:Name="ImagePickerRootGrid" Background="Gray">
        <Image Source="{Binding Source, ElementName=ImagePickerUserControl}"/>
    </Grid>

</UserControl>

和代码部分,对不起长度,但我相信这里一切都很重要。

public sealed partial class ImagePicker : UserControl
{
    public ImagePicker()
    {
        this.InitializeComponent();

        // Hookup event to handle when the control is tapped
        this.Tapped += ImagePicker_Tapped;
    }

    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(ImageSource), typeof(ImagePicker),
        new PropertyMetadata(null, new PropertyChangedCallback(ImagePicker.OnSourceChanged)));

    public ImageSource Source
    {
        get
        {
            return (ImageSource)this.GetValue(ImagePicker.SourceProperty);
        }

        set
        {
            this.SetValue(ImagePicker.SourceProperty, value);
        }
    }

    private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // Update Visual State
    }

    private async void ImagePicker_Tapped(object sender, TappedRoutedEventArgs e)
    {
        // Pick up a new picture
        FileOpenPicker filePicker = new FileOpenPicker();
        filePicker.FileTypeFilter.Add(".jpg");
        filePicker.FileTypeFilter.Add(".jpeg");
        filePicker.FileTypeFilter.Add(".png");
        var pngFile = await filePicker.PickSingleFileAsync();

        // If the user picked up a file
        if (pngFile != null)
        {
            BitmapImage bitmap = new BitmapImage();
            await bitmap.SetSourceAsync(await pngFile.OpenReadAsync());

            // Update the source image
            this.Source = bitmap;
        }
    }
}

我相信这个问题只是我的一个错误,但我无法理解这里发生了什么。如果您想尝试运行该项目并更好地查看代码,我将其上传并分享到 SkyDrive:ImageUserControl

感谢您耐心阅读这么长的帖子。

4

2 回答 2

1

如果您在运行代码时查看输出窗口,您将看到以下内容:-

mscorlib.dll 中出现了“System.ArgumentException”类型的第一次机会异常

错误:无法将值从目标保存回源。BindingExpression:路径='PictureUri' DataItem='ImageUserControl.PictureViewModel'; 目标元素是'ImageUserControl.ImagePicker'(名称='ImagePickerUserControl');目标属性是“源”(类型“ImageSource”)。

这是因为您将 ImageSource 绑定到 URI 的属性。最简单的解决方法是将图像选择器的源更改为 uri,如下所示:-

using System.ComponentModel;
using Windows.UI.Xaml.Media;

namespace ImageUserControl
{
    public class PictureViewModel : INotifyPropertyChanged
    {
        private ImageSource pictureUri;

        public ImageSource PictureUri 
        { 
            get
            {
                return this.pictureUri;
            }

            set 
            {
                if (this.pictureUri != value)
                {
                    this.pictureUri = value;
                    this.RaisePropertyChanged("PictureUri");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            var handler = this.PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

然后,您可以按如下方式修改视图模型定位器:-

using System;
using Windows.UI.Xaml.Media.Imaging;

namespace ImageUserControl
{
    public class ViewModelLocator
    {
        static ViewModelLocator()
        {}

        public PictureViewModel Main
        {
            get
            {
                return new PictureViewModel
                {                    
                    PictureUri = new BitmapImage(new Uri("ms-resource:/Files/Assets/eels.jpg"))
                };
            }
        }
    }
}

然后该事件会按您的预期触发。如果您确实需要图像的 URI,则必须将其添加为附加属性。

(使用 Eels 专辑封面作为测试图像的奖励积分)。

于 2012-12-31T11:07:36.677 回答
1

双向绑定不起作用,因为您的依赖属性是 type ImageSource,而您的视图模型属性是 type Uri。绑定无法将 an 转换ImageSource为 an,Uri因此未设置该值。您需要Uri用户控件上的类型属性来使双向绑定起作用。

编辑:

如果您仅将依赖项属性更改为不同的类型,则如果用户选择了您的应用在没有选择器的情况下无法访问的文件,则内部图像将不再显示。您的应用程序只能通过使用返回的来访问此类文件StorageFile,而不是使用其绝对路径。在控件内部,您可以通过具有两个依赖属性来解决这个问题:ImageSource就像现在显示内部图像和Uri返回路径一样。由于您将绑定到第二个,因此您需要添加一个回调,该回调将ImageSource在“Uri”从外部更改时设置属性。

根据您想对用户控制之外的结果做什么,这对您来说可能还不够好。如果您想访问那里的文件,您需要返回 aStorageFile或将文件放入FutureAccessList并返回令牌。

于 2012-12-24T06:00:16.220 回答