Стиль для изменения изображений на кнопках в диалоге

Не могу заставить работать следующее, должно быть не хватает чего-то элементарного. Моя цель - создать стиль в диалоговом окне (окне), чтобы установить изображение на кнопке внутри него. Итак, что у меня есть в коде диалога, я добавил DependencyProperty следующим образом:

public static readonly DependencyProperty ImageRefreshProperty =
  DependencyProperty.Register(nameof(ImageRefreshProperty), typeof(ImageSource),
    typeof(MyDlg), new PropertyMetadata(new BitmapImage(
      new Uri(@"pack://application:,,,/component/Resources/refresh.png"))));
public ImageSource ImageRefresh {
  get { return (ImageSource)GetValue(ImageRefreshProperty); }
  set { SetValue(ImageRefreshProperty, value); }
}

В Xaml у меня есть это:

<Button DockPanel.Dock="Left" Style="{StaticResource buttonIcon}">
  <Image Source="{Binding Path=ImageRefresh,
      RelativeSource={RelativeSource AncestorType=local:MyDlg}}" />
</Button>

Это отлично работает, если я использую код для изменения изображения, например

dlg.ImageRefresh = new BitmapImage(
  new Uri("pack://application:,,,/component/Resources/refr.png"));

Но в идеале я хотел бы установить изображение с помощью стиля, например, следующим образом:

<Style TargetType="{x:Type MyDlg}">
  <Setter Property="ImageRefresh" Value="pack://application:,,,/component/Resources/refr.png" />
</Style>

Я получаю следующую ошибку:

System.Windows.Markup.XamlParseException:
''Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' 
Inner Exception System.Windows.Markup.XamlParseException:
ArgumentNullException: Key cannot be null. Arg_ParamName_Name 

Я также пробовал Setter Value, который определяет внутри него BitmapImage вместо строки, но все равно получаю ту же ошибку:

<Setter Property="ImageRefresh">
  <Setter.Value>
    <BitmapImage UriSource="pack://application:,,,/component/Resources/refr.png"/>
  </Setter.Value>
</Setter>

Установка точки останова для получателя / установщика DependencyProperty даже не затрагивает, равно как и преобразователь при привязке источника изображения.

Что мне здесь не хватает?

Изменить: чтобы узнать, имеет ли ImageSource какое-либо отношение к этому, я протестировал свой код с другим свойством типа bool? для установки свойства IsEnabled кнопки в диалоговом окне, но результат тот же. Таким образом, ошибка связана не с изображением, его URL-адресом пакета (который, кстати, работает), а, по-видимому, с чем-то еще.


person Daap    schedule 26.01.2021    source источник
comment
Интересно, как этот Pack URI должен работать. У вас действительно есть /component папка верхнего уровня в вашем проекте Visual Studio? В противном случае URI должен быть pack://application:,,,/Resources/refr.png или pack://application:,,,/AssemblyName;component/Resources/refr.png.   -  person Clemens    schedule 26.01.2021
comment
А где именно этот стиль декларировать?   -  person Clemens    schedule 26.01.2021
comment
URI пакета не является проблемой. Как уже говорилось, он отлично работает при установке изображения с помощью кода, но попытка установить его с помощью стиля - это то, что дает ошибку. Я также отредактировал вопрос с помощью другого теста, который я провел со свойством типа bool? вместо ImageSource.   -  person Daap    schedule 26.01.2021
comment
Стиль установлен в моем списке стилей, используемых для многих других вещей (я упростил код вопроса, но он является частью большой базы кода), и в диалоговом окне установлен этот стиль (на самом деле удаление этого будет работать без проблема, но, очевидно, не с изменением ожидаемого свойства).   -  person Daap    schedule 26.01.2021


Ответы (2)


Я сам нашел ответ, немного покопавшись в своем коде. Проблема заключалась в определении DependencyProperty. В моем коде было:

public static readonly DependencyProperty ImageRefreshProperty =
  DependencyProperty.Register(nameof(ImageRefreshProperty) /*Wrong*/,
    typeof(ImageSource),
    typeof(MyDlg), new PropertyMetadata(new BitmapImage(
      new Uri(@"pack://application:,,,/component/Resources/refresh.png"))));

но должно быть:

public static readonly DependencyProperty ImageRefreshProperty =
  DependencyProperty.Register(nameof(ImageRefresh) /*Correct*/,
    typeof(ImageSource),
    typeof(MyDlg), new PropertyMetadata(new BitmapImage(
      new Uri(@"pack://application:,,,/component/Resources/refresh.png"))));

Очень маленькая оплошность с большими последствиями ...

person Daap    schedule 26.01.2021
comment
Сработала ли установка DP извне вашего диалога? Я все еще получал ошибки при настройке с App.xaml. То же значение, установленное из кода программной части или разметка диалогового окна, работало без проблем. - person D M; 27.01.2021
comment
Да, теперь он отлично работает из стиля. - person Daap; 27.01.2021

Внутреннее исключение System.Windows.Markup.XamlParseException: ArgumentNullException: ключ не может быть нулевым. Arg_ParamName_Name

Судя по сообщению об ошибке, на вашем Style.

<Style x:Key="MyDialogStyle" TargetType="{x:Type MyDlg}">
    <Setter Property="ImageRefresh Value="..."/>
</Style>

Согласно этому ответу, вы можете использовать x:Key={x:Type MyDlg}", если не хотите устанавливать явный ключ.

<Style x:Key="{x:Type MyDlg}" TargetType="{x:Type MyDlg}">
    <Setter Property="ImageRefresh Value="..."/>
</Style>
person D M    schedule 26.01.2021
comment
Боюсь, дело не в этом. Я немного очистил свой код, чтобы ответить на вопрос, касающийся SO, но на самом деле у моего стиля был ключ, но я все равно получаю сообщение об ошибке. - person Daap; 26.01.2021
comment
Хм, я работаю над репродукцией. Буду обновлять завтра. - person D M; 26.01.2021
comment
Теперь я точно уверен, что string сеттер не работает, поскольку DependencyProperty ожидает ImageSource, но вы это уже заметили. Мне показалось, что сеттер / получатель никогда не работал, потому что фреймворк выполнял некоторую проверку на значение свойства по умолчанию во время инициализации. - person D M; 26.01.2021
comment
Стиль в ResourceDictionary никогда не нуждается в x:Key, пока TargetType уникален. Если вы его опустите, для ключа неявно будет установлено значение TargetType. - person Clemens; 26.01.2021
comment
Комментарий по поводу установщика строки тоже не имеет смысла. Существует встроенное преобразование типа из строкового в целевые типы, такие как ImageSource. - person Clemens; 26.01.2021