2012-12-23 89 views
2

我正在開發用於Metro UI的ImagePicker用戶控件。它的原理很簡單:它顯示圖像,並且當圖像被點擊時,打開文件對話框以允許改變當前圖像。爲了實現這一點,用戶控件只需公開包裝圖像綁定到的ImageSource屬性。XAML:用戶控件不傳播更改到綁定源

<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

感謝您耐心閱讀這麼長的帖子。

+0

當您刪除異步修改器時會發生什麼?前段時間,有一個錯誤[異常不是使用異步引發的](http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/bea154b0-08b0-4fdc-be31- 058d9f5d1c4e)。另外,我不完全確定,但不能使用異步來更新UI線程上的某些內容。 –

+0

@MetroSmurf我希望我可以嘗試,但當然,文件選取器不提供同步方法。我要用硬編碼的字符串嘗試。 – Ucodia

+0

@MetroSmurf我只是同步嘗試,一切仍然表現相同。 – Ucodia

回答

1

雙向綁定不起作用,因爲您的依賴屬性的類型爲ImageSource,而您的視圖模型屬性的類型爲Uri。該綁定無法將ImageSource轉換爲Uri,因此該值未設置。您需要在用戶控件上輸入Uri的屬性以使雙向綁定工作正常。

編輯:

如果只依賴屬性更改爲不同的類型,如果用戶選擇了一個文件,你的應用程序不會有沒有揀貨機進入內圖像不會顯示任何更多。您的應用只能使用返回的StorageFile訪問此類文件,但不能使用其絕對路徑。在控件內部,可以通過具有兩個依賴屬性來解決這個問題:ImageSource像現在一樣顯示內部圖像,Uri返回路徑。既然你會綁定到第二個,你需要添加一個回調,當'Uri'從外部改變時將會設置ImageSource屬性。

根據您想要對用戶控制之外的結果執行的操作,這對您而言可能還不夠好。如果您想要訪問該文件,則需要返回StorageFile或將該文件放入FutureAccessList並返回該令牌。

+0

這次,視圖模型接收到更改,但內部圖像不會更改,但會消失。 – Ucodia

+0

@Ucodia我包括一些額外的解釋。 –

1

如果你看看輸出窗口,當你正在運行的代碼,你會看到以下內容: -

A first chance exception of type 'System.ArgumentException' occurred in mscorlib.dll

Error: Cannot save value from target back to source. BindingExpression: Path='PictureUri' DataItem='ImageUserControl.PictureViewModel'; target element is 'ImageUserControl.ImagePicker' (Name='ImagePickerUserControl'); target property is 'Source' (type '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,那麼你將不得不添加它作爲一個額外的屬性。

(使用鰻魚專輯封面作爲測試圖片的獎勵積分)。

+0

我想過,但我不喜歡的是,我不得不將System.Windows.Media.Imaging命名空間添加到我的視圖模型中。沒有這麼大的交易,但我有點不願意在視圖模型中使用圖形化概念。但是,如果沒有其他解決方案出現,我一定會更多地考慮它。謝謝。 – Ucodia