用户控件不将更改传播到绑定源
本文关键字:传播 绑定 控件 用户 | 更新日期: 2023-09-27 17:49:17
我正在为Metro UI开发ImagePicker用户控件。它的原理很简单:它显示图像,当点击图像时,打开一个文件对话框,允许更改当前图像。要实现这一点,用户控件只需公开一个ImageSource属性,包装后的图像将绑定到该属性。
<local:ImagePicker Source="{Binding PictureUri, Mode=TwoWay}"/>
在启动时,绑定工作正常,并显示来自视图模型提供的PictureUri属性的图片。问题是,当我点击图像并选择一个新的图像时,显示新的图像,但是绑定值没有在我的视图模型中更新,尽管有双向绑定模式。我相信这个问题来自我的用户控制代码,但我不明白为什么值不传播到视图模型时,它实际上是传播到包装图像…
这里是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
感谢您的耐心阅读这么长的帖子。
双向绑定不起作用,因为你的依赖属性是ImageSource
类型,而你的视图模型属性是Uri
类型。绑定不能将ImageSource
转换为Uri
,因此没有设置该值。您需要在用户控件上设置一个类型为Uri
的属性,以使双向绑定工作。
如果你只是将依赖属性更改为不同的类型,那么当用户选择了一个你的应用程序在没有选择器的情况下无法访问的文件时,内部图像将不再显示。您的应用程序只能通过使用返回的StorageFile
来访问这样的文件,但不使用其绝对路径。在控件内部,您可以通过使用两个依赖属性来解决这个问题:ImageSource
(现在用于显示内部图像)和Uri
(用于返回路径)。因为你将绑定到第二个,你需要添加一个回调,当'Uri'从外部改变时,它将设置ImageSource
属性。
根据您想对用户控制之外的结果做什么,这可能仍然不够好。如果你想访问那里的文件,你要么需要返回一个StorageFile
,要么把文件放在FutureAccessList中并返回令牌。
如果您在运行代码时查看输出窗口,您将看到以下内容:-
类型为'System '的第一次异常。
mscorlib.dll出现ArgumentException错误:无法将值从目标保存回源。BindingExpression: Path='PictureUri' DataItem='ImageUserControl.PictureViewModel';目标元素是"ImageUserControl"。image picker"(Name = ' ImagePickerUserControl ');目标属性为'Source'(类型为'ImageSource')。
这是因为您正在将ImageSource绑定到URI的属性。最简单的修复方法是将imagepicker的源代码更改为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专辑封面作为测试图像的加分项)。