如何在DependencyProperty
的自定义wpf控件上实现ImageSource
?
我创建了一个自定义控件(按钮),其中包括显示图像。我希望能够从控件外部为图像设置ImageSource,因此我实现了DependencyProperty。每当我尝试更改ImageSource时,我得到一个SystemInvalidOperationException
:"调用线程无法访问此对象,因为另一个线程拥有它。"
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;
}
答案 0 :(得分:1)
如果您在内部使用图片,则有必要重复使用Image.SourceProperty
而不是ImageBrush
。
确保在UI线程上创建所有线程仿射元素,或者如果它们是Freeze
则需要freezable,然后才能与它们进行交叉线程。 (ImageSource
是Freezable
)
属性更改处理程序没有连接,所以它永远不会被调用,但是它的内容无论如何都是无意义的,在调用处理程序时已经设置了属性。