Как реализовать DependencyProperty на пользовательском элементе управления wpf для ImageSource? - PullRequest
1 голос
/ 06 декабря 2011

Как реализовать 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" />

Адаптировал приведенный выше исходный код, чтобы отразить мой прогресс.

Решение:

Код, указанный выше, работает нормально. Важным изменением по сравнению с первоначальной версией является добавление метода Freeze () из потока пользовательского интерфейса (см. Принятый ответ). Фактическая проблема в моем проекте не в том, что кнопка не инициализируется в потоке пользовательского интерфейса, , но новое изображение устанавливается из другого потока. Изображение устанавливается в обработчике событий, который сам запускается из другого потока. Я решил проблему с помощью 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 Ответ

1 голос
/ 06 декабря 2011
  1. Если вы используете изображение для внутреннего использования, имеет смысл повторно использовать Image.SourceProperty, а не ImageBrush.

  2. Обязательно создайте все аффинно-зависимые элементы в UI-потоке, или вам нужно Freeze их, если они freezable , прежде чем делать что-либо перекрестное нить с ними. (ImageSource является Freezable)

  3. Обработчик измененного свойства не подключен, поэтому он никогда не будет вызываться, его содержимое все равно не имеет смысла, хотя свойство уже было установлено при вызове обработчика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...