1

DependencyPropertyのカスタム wpf コントロールにを実装するにはどうすればよいImageSourceですか?

とりわけ画像を表示するカスタム コントロール (ボタン) を作成しました。コントロールの外側から画像の ImageSource を設定できるようにしたいので、DependencyProperty を実装しました。ただし、ImageSource を変更しようとすると、SystemInvalidOperationException別のスレッドが所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません。」というメッセージが表示されます。

OK、メイン スレッドはイメージ コントロールにアクセスできないので、Dispatcher を使用する必要がありますが、どこでどのように行うのでしょうか? どうやら例外はセッターでスローされ、実行されますSetValue(ImageProperty, value);

tv_CallStart.xaml:

<Button x:Class="EHS_TAPI_Client.Controls.tv_CallStart" x:Name="CallButton"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="24" d:DesignWidth="24" Padding="0" BorderThickness="0"
         Background="#00000000" BorderBrush="#FF2467FF" UseLayoutRounding="True">

         <Image x:Name="myImage"
                Source="{Binding ElementName=CallButton, Path=CallImage}" />
</Button>

tv_CallStart.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace EHS_TAPI_Client.Controls
{
    public partial class InitiateCallButton : Button
    {
        public ImageSource CallImage
        {
            get { return (ImageSource)GetValue(CallImageProperty); }
            set { SetValue(CallImageProperty, value); }
        }
        public static readonly DependencyProperty CallImageProperty =
            DependencyProperty.Register("CallImage", typeof(ImageSource), typeof(InitiateCallButton), new UIPropertyMetadata(null));

        public InitiateCallButton()
        {
            InitializeComponent();
        }
    }
}

UI スレッドのコード ビハインドから画像を設定します。

BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri("pack://application:,,,/EHS-TAPI-Client;component/Images/call-start.png");
bi.EndInit();
bi.Freeze();
CallButton.CallImage = bi;

コントロールが初期化される MainWindow.xaml:

<ctl:InitiateCallButton x:Name="CallButton" CallImage="/Images/call-start.png" />

私の進歩を反映するために上記のソースコードを適応させました..

解決:

上記のコードは正常に動作しています。初期バージョンからの重要な変更点は、UI スレッドからの Freeze() メソッドの追加です (受け入れられた回答を参照)。私のプロジェクトの実際の問題は、ボタンが UI スレッドで初期化されていないことではなく、新しい画像が別のスレッドから設定されていることです。イメージは、別のスレッドからトリガーされるイベント ハンドラーに設定されます。を使用して問題を解決しましたDispatcher

BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri("pack://application:,,,/EHS-TAPI-Client;component/Images/call-start.png");
bi.EndInit();
bi.Freeze();
if (!Application.Current.Dispatcher.CheckAccess())
{
    Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate()
        {
            CallButton.CallImage = bi;
        });
}
else
{
    CallButton.CallImage = bi;
}
4

1 に答える 1

1
  1. Image.SourcePropertyイメージを内部で使用する場合は、 のイメージではなくを再利用するのが理にかなっていImageBrushます。

  2. すべてのスレッド アフィン要素を UI スレッド上に作成するか、クロススレッドを実行する前にフリーズFreeze可能である場合はそれらを作成する必要があります。(は)ImageSourceFreezable

  3. プロパティ変更ハンドラーは接続されていないため、呼び出されることはありません。その内容はとにかく無意味ですが、ハンドラーが呼び出されたときにプロパティは既に設定されています。

于 2011-12-06T11:46:15.880 に答える