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

ImageSource依存関係プロパティが typeであり、ビュー モデル プロパティがtype であるため、双方向バインディングは機能しませんUriImageSourceバインディングは を に変換できないUriため、値は設定されません。Uri双方向バインディングを機能させるには、ユーザー コントロールにtype のプロパティが必要です。

編集:

依存関係プロパティを別の型に変更しただけでは、ピッカーがないとアプリがアクセスできないファイルをユーザーが選択すると、内側の画像は表示されなくなります。アプリは、返された を使用してのみそのようなファイルにアクセスできますが、StorageFileその絶対パスは使用しません。コントロール内では、2 つの依存関係プロパティを使用することで解決できます。ImageSourceたとえば、内側の画像を表示しUri、パスを返すためです。ImageSource2 番目のものにバインドするため、「Uri」が外部から変更されたときにプロパティを設定するコールバックを追加する必要があります。

ユーザー コントロール外の結果をどうしたいかによっては、これでも十分ではない場合があります。そこにあるファイルにアクセスしたい場合は、 を返すStorageFileか、ファイルをFutureAccessListに入れてトークンを返す必要があります。

于 2012-12-24T06:00:16.220 に答える
1

コードを実行しているときに出力ウィンドウを見ると、次のように表示されます。

タイプ 'System.ArgumentException' の初回例外が mscorlib.dll で発生しました

エラー: 値をターゲットからソースに保存できません。BindingExpression: Path='PictureUri' DataItem='ImageUserControl.PictureViewModel'; ターゲット要素は 'ImageUserControl.ImagePicker' (Name='ImagePickerUserControl') です。ターゲット プロパティは 'Source' (タイプ '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 に答える