将 XAMLCropControl ImageSource 绑定到 ViewModel 中的 ImageSource 属性 失败
Binding XAMLCropControl ImageSource to ImageSource property in ViewModel failed
我正在使用 XamlCropControl 并尝试在我的视图模型中绑定它的 ImageSource
属性。
private ImageSource source;
public ImageSource Source
{
get { return source; }
set { SetProperty(ref source, value); }
}
图片是从用户图库中挑选的 StorageFile
private async void setImageSource()
{
if (ImageStorageFile != null)
{
var imageProperties = await ImageStorageFile.Properties.GetImagePropertiesAsync();
WriteableBitmap wb = new WriteableBitmap((int)imageProperties.Width, (int)imageProperties.Height);
IRandomAccessStream fileStream = await ImageStorageFile.OpenAsync(FileAccessMode.Read);
wb.SetSource(fileStream);
Source = wb;
Show();
}
}
在我的 XAML 我有以下内容
<xamlcrop:CropControl Grid.Row="1" x:Name="cropControl" ImageSource="{Binding Source}" DesiredAspectRatio="{Binding AspectRatio, Mode=TwoWay}" />
但是图像没有显示。但是如果我使用示例中的路径,例如
<xamlcrop:CropControl x:Name="Crop" ImageSource="ms-appx:///Assets/wrench.jpg" />
有效。我在 CropControl.cs
中设置了一个断点,实际上 Writeablebitmap
被传递给了依赖项 属性 但它没有显示。我错过了什么?
假设您已正确完成所有关于数据绑定的事情,那么根据您提供的 XamlCropControl
的开源代码,您已将 WriteableBitmap
设置为 Source
的 CropControl
。
可以参考CropControl
的源码,在它的Setup()
和DoFullLayout()
方法中,是用来在这个控件上渲染图片源的,代码如下这个:
public void Setup()
{
// Check for loaded and template succesfully applied
if (!_isLoaded ||
!_isTemplateApplied)
{
return;
}
_image.Source = ImageSource;
var bi = _image.Source as BitmapImage;
if (bi != null)
{
...
}
}
private void DoFullLayout()
{
if (!_isTemplateApplied)
{
return;
}
var bi = _image.Source as BitmapImage;
if (bi == null)
{
return;
}
...
}
正如你在这里看到的,它使用 as
将图像源投射到 BitmapImage
,因为你的源是 WriteableBitmap
,这里它将无法投射并且 return 空。这是您遇到问题的第一个可能原因。如果您坚持要使用WriteableBitmap
,则需要修改这些代码,将BitmapImage
更改为您的WriteableBitmap
。
另一个可能的问题是它的 Setup
方法:
var bi = _image.Source as WriteableBitmap;
if (bi != null)
{
bi.ImageOpened += (sender, e) =>
{
DoFullLayout();
if (this.ImageOpened != null)
{
this.ImageOpened(this, e);
}
};
}
如果您将 BitmapImage
作为源传递,当我使用 UriSource
生成此 BitmapImage
时,一切都会正常进行。但是当我使用 SetSource
将文件流设置为这个 BitmapImage
时,ImageOpened
事件将神奇地 NOT 在我身边触发,我'我不确定这里会发生什么。但是你使用的是WriteableBitmap
,没有WriteableBitmap
的ImageOpend
事件,无论如何你都需要修改这段代码。例如,我现在将其更改为:
var bi = _image.Source as WriteableBitmap;
if (bi != null)
{
//bi.ImageOpened += (sender, e) =>
//{
// DoFullLayout();
// if (this.ImageOpened != null)
// {
// this.ImageOpened(this, e);
// }
//};
try
{
DoFullLayout();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
现在可以了,你可以自己处理异常了。
既然你没有提到你用哪个模板开发UWP应用程序,我这里只是用标准方法来提供一个演示,以防你在数据绑定方面有问题:
主页xaml:
<Page.DataContext>
<local:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
...
<Border Grid.Row="0" BorderBrush="Red" BorderThickness="1">
<xamlcrop:CropControl x:Name="Crop" ImageSource="{Binding Source}" DesiredAspectRatio="1.0" />
</Border>
<Button Content="Pick Image" Command="{Binding SetImageSource}" Grid.Row="1" />
MainPageViewModel:
public class MainPageViewModel : INotifyPropertyChanged
{
public MainPageViewModel()
{
source = null;
}
public ICommand SetImageSource
{
get
{
return new CommandHandler(() => this.setImageSource());
}
}
public async void setImageSource()
{
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/wrench.jpg"));
if (file != null)
{
using (var stream = await file.OpenReadAsync())
{
WriteableBitmap wb = new WriteableBitmap(960, 1200);
wb.SetSource(stream);
Source = wb;
}
}
else
{
}
}
private ImageSource source;
public ImageSource Source
{
get { return source; }
set
{
if (value != source)
{
source = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
我的CommandHandler
是这样简单的:
public class CommandHandler : ICommand
{
public event EventHandler CanExecuteChanged;
private Action _action;
public CommandHandler(Action action)
{
this._action = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
this._action();
}
}
我正在使用 XamlCropControl 并尝试在我的视图模型中绑定它的 ImageSource
属性。
private ImageSource source;
public ImageSource Source
{
get { return source; }
set { SetProperty(ref source, value); }
}
图片是从用户图库中挑选的 StorageFile
private async void setImageSource()
{
if (ImageStorageFile != null)
{
var imageProperties = await ImageStorageFile.Properties.GetImagePropertiesAsync();
WriteableBitmap wb = new WriteableBitmap((int)imageProperties.Width, (int)imageProperties.Height);
IRandomAccessStream fileStream = await ImageStorageFile.OpenAsync(FileAccessMode.Read);
wb.SetSource(fileStream);
Source = wb;
Show();
}
}
在我的 XAML 我有以下内容
<xamlcrop:CropControl Grid.Row="1" x:Name="cropControl" ImageSource="{Binding Source}" DesiredAspectRatio="{Binding AspectRatio, Mode=TwoWay}" />
但是图像没有显示。但是如果我使用示例中的路径,例如
<xamlcrop:CropControl x:Name="Crop" ImageSource="ms-appx:///Assets/wrench.jpg" />
有效。我在 CropControl.cs
中设置了一个断点,实际上 Writeablebitmap
被传递给了依赖项 属性 但它没有显示。我错过了什么?
假设您已正确完成所有关于数据绑定的事情,那么根据您提供的 XamlCropControl
的开源代码,您已将 WriteableBitmap
设置为 Source
的 CropControl
。
可以参考CropControl
的源码,在它的Setup()
和DoFullLayout()
方法中,是用来在这个控件上渲染图片源的,代码如下这个:
public void Setup()
{
// Check for loaded and template succesfully applied
if (!_isLoaded ||
!_isTemplateApplied)
{
return;
}
_image.Source = ImageSource;
var bi = _image.Source as BitmapImage;
if (bi != null)
{
...
}
}
private void DoFullLayout()
{
if (!_isTemplateApplied)
{
return;
}
var bi = _image.Source as BitmapImage;
if (bi == null)
{
return;
}
...
}
正如你在这里看到的,它使用 as
将图像源投射到 BitmapImage
,因为你的源是 WriteableBitmap
,这里它将无法投射并且 return 空。这是您遇到问题的第一个可能原因。如果您坚持要使用WriteableBitmap
,则需要修改这些代码,将BitmapImage
更改为您的WriteableBitmap
。
另一个可能的问题是它的 Setup
方法:
var bi = _image.Source as WriteableBitmap;
if (bi != null)
{
bi.ImageOpened += (sender, e) =>
{
DoFullLayout();
if (this.ImageOpened != null)
{
this.ImageOpened(this, e);
}
};
}
如果您将 BitmapImage
作为源传递,当我使用 UriSource
生成此 BitmapImage
时,一切都会正常进行。但是当我使用 SetSource
将文件流设置为这个 BitmapImage
时,ImageOpened
事件将神奇地 NOT 在我身边触发,我'我不确定这里会发生什么。但是你使用的是WriteableBitmap
,没有WriteableBitmap
的ImageOpend
事件,无论如何你都需要修改这段代码。例如,我现在将其更改为:
var bi = _image.Source as WriteableBitmap;
if (bi != null)
{
//bi.ImageOpened += (sender, e) =>
//{
// DoFullLayout();
// if (this.ImageOpened != null)
// {
// this.ImageOpened(this, e);
// }
//};
try
{
DoFullLayout();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
现在可以了,你可以自己处理异常了。
既然你没有提到你用哪个模板开发UWP应用程序,我这里只是用标准方法来提供一个演示,以防你在数据绑定方面有问题:
主页xaml:
<Page.DataContext>
<local:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
...
<Border Grid.Row="0" BorderBrush="Red" BorderThickness="1">
<xamlcrop:CropControl x:Name="Crop" ImageSource="{Binding Source}" DesiredAspectRatio="1.0" />
</Border>
<Button Content="Pick Image" Command="{Binding SetImageSource}" Grid.Row="1" />
MainPageViewModel:
public class MainPageViewModel : INotifyPropertyChanged
{
public MainPageViewModel()
{
source = null;
}
public ICommand SetImageSource
{
get
{
return new CommandHandler(() => this.setImageSource());
}
}
public async void setImageSource()
{
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/wrench.jpg"));
if (file != null)
{
using (var stream = await file.OpenReadAsync())
{
WriteableBitmap wb = new WriteableBitmap(960, 1200);
wb.SetSource(stream);
Source = wb;
}
}
else
{
}
}
private ImageSource source;
public ImageSource Source
{
get { return source; }
set
{
if (value != source)
{
source = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
我的CommandHandler
是这样简单的:
public class CommandHandler : ICommand
{
public event EventHandler CanExecuteChanged;
private Action _action;
public CommandHandler(Action action)
{
this._action = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
this._action();
}
}