【问题标题】:Binding XAMLCropControl ImageSource to ImageSource property in ViewModel failed将 XAMLCropControl ImageSource 绑定到 ViewModel 中的 ImageSource 属性失败
【发布时间】:2016-11-12 04:52:30
【问题描述】:

我正在使用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 已传递给dependencyproperty,但未显示。我错过了什么?

【问题讨论】:

    标签: xaml binding uwp crop windows-10-universal


    【解决方案1】:

    假设你已经完成了所有关于数据绑定的事情,那么根据你提供的XamlCropControl的开源,从你的代码中,你设置了一个WriteableBitmap作为Source的@987654324 @。

    你可以参考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,所以在这里它将无法转换并返回null。这是您的问题的第一个可能原因。如果您坚持使用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 事件将神奇地在我身边被触发,我不确定这里会发生什么。但是您使用的是WriteableBitmap,没有WriteableBitmapImageOpend 事件,无论如何您都需要修改此代码。比如我现在改成这样:

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

    【讨论】:

    • 优秀。我正在使用 Template10,但我可以根据您的建议进行相应调整。
    猜你喜欢
    • 2014-11-21
    • 1970-01-01
    • 2016-02-02
    • 2014-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    • 1970-01-01
    相关资源
    最近更新 更多