如何在ImageSource的自定义wpf控件上实现DependencyProperty?

时间:2011-12-06 11:31:16

标签: wpf dependency-properties imagesource

如何在DependencyProperty的自定义wpf控件上实现ImageSource

我创建了一个自定义控件(按钮),其中包括显示图像。我希望能够从控件外部为图像设置ImageSource,因此我实现了DependencyProperty。每当我尝试更改ImageSource时,我得到一个SystemInvalidOperationException"调用线程无法访问此对象,因为另一个线程拥有它。"

好的,所以主线程无法访问图像控件,所以我需要使用Dispatcher - 但是在哪里以及如何?显然,异常会在setter中抛出,执行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()方法(请参阅接受的答案)。 my 项目中的实际问题不是按钮而不是在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;
}

1 个答案:

答案 0 :(得分:1)

  1. 如果您在内部使用图片,则有必要重复使用Image.SourceProperty而不是ImageBrush

  2. 确保在UI线程上创建所有线程仿射元素,或者如果它们是Freeze则需要freezable,然后才能与它们进行交叉线程。 (ImageSourceFreezable

  3. 属性更改处理程序没有连接,所以它永远不会被调用,但是它的内容无论如何都是无意义的,在调用处理程序时已经设置了属性。