0

名前で画像を取得し、オブジェクトを返す WPF マークアップ拡張機能がありBitmapImageます。

<Image Source="{my:ImageProvider ImageName=myImageName}"></Image>

画像の取得には数秒かかる操作なので、デフォルトの画像を表示し、準備ができたら要求された画像を表示したいと思います。

私がやろうとしたのはこのようなものですが、これはBitmapImageオブジェクトを変更する可能性があるため、UI を更新しません (サンプル コード):

BitmapImage img;
public override object ProvideValue(IServiceProvider serviceProvider)
{
    img = new BitmapImage(new Uri(@"D:\defaultImage.png", UriKind.Absolute));

    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
    bw.RunWorkerAsync();

    return img;
}

void bw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    System.Threading.Thread.Sleep(5000);
}

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    img.UriSource = new Uri(@"D:\actualImage.png", UriKind.Absolute);
}

BitmapImage変更されたもの(INotifyPropertyChanged など)を使用するように UI を更新する方法はありますか、またはこれを達成するための別のアプローチはありますか?

4

2 に答える 2

1

PriorityBindingあなたが探しているものだと思います。実際の画像ソースを最高のバインディングとして 2 つの異なる DP にバインドできIsAsync、そのバインディングのプロパティを true に設定することを忘れないでください。イメージ ソースの準備が整うと、2 番目のバインディングが自動的に置き換えられます。

開始するには、このリンクを参照してください - http://msdn.microsoft.com/en-us/library/system.windows.data.prioritybinding.aspx

于 2011-12-18T16:46:06.730 に答える
0

これを行うには2つの方法がありました。どちらの方法でも、画像をラップして実装するクラスを使用しますINotifyPropertyChanged

class ImageSourceWrapper : ObservableObject
{
    private ImageSource _image;
    public ImageSource Image
    {
        get { return _image; }
        set
        {
            if (value != _image)
            {
                _image = value;

                RaiseOnPropertyChanged("Image");
            }
        }
    }

    public ImageSourceWrapper(ImageSource image)
    {
        Image = image;
    }
}

最初のアプローチ

これを取得したら、次のように、マークアップ拡張機能でImageSourceWrapperオブジェクトを返してバインドすることができます。

<Image Source="{Binding Source={my:ImageProvider ImageName=myImageName}, Path=Image}" />

私はこの方法があまり好きではありませんでした。かなり面倒で、ImageSourceWrapper単純に を操作するのではなく、クラスを知らなければならないからImageSourceです。それから私は2番目のアプローチを思いつきました。

第二のアプローチ

このアプローチでもImageSourceWrapperクラスを使用しますが、マークアップ拡張機能にImageSourceWrapperオブジェクトを返す代わりに、オブジェクトにバインドするように設定したバインディング オブジェクトを返しImageSourceWrapperます。

マークアップ拡張機能は次のようになります。

private ImageSourceWrapper _imageSourceWrapper;
public override object ProvideValue(IServiceProvider serviceProvider)
{
    // Get the object and the property to be bound.
    IProvideValueTarget service = IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget));
    DependencyObject targetObject = service.TargetObject as DependencyObject;
    DependencyProperty targetProperty = service.TargetProperty as DependencyProperty;

    // Set up the binding with the default image.
    _imageSourceWrapper = new ImageSourceWrapper(DefaultImage);
    Binding binding = new Binding("Image");
    binding.Source = _imageSourceWrapper;
    BindingOperations.SetBinding(targetObject, targetProperty, binding);

    // Retrieve the actual image asynchronously.
    GetImageAsync();

    return binding.ProvideValue(serviceProvider);
}

private void GetImageAsync()
{
    // Get the image asynchronously.

    // Freeze the image so it could be accessed from all threads regardless
    // of which thread it was created on.
    newImage.Freeze();

    // Got the image - update the _imageSourceWrapper object.
    _imageSourceWrapper = newImage;
}

次に、このように XAML で使用できます

<Image Source="{my:ImageProvider ImageName=myImageName}" />

このようにして、デフォルトの画像が最初に表示され、要求された画像が取得されると、代わりに表示されます。

ここのコードが完全に正しくない場合は申し訳ありませんが、現時点ではコードに近づいていません。願わくば、現時点では主なアイデアを表現するにはこれで十分です。

于 2012-01-07T13:11:44.480 に答える