Элемент панели инструментов Привязка DataTemplate При поиске RelativeSource не удалось найти родительскую панель инструментов
У меня есть панель инструментов, содержащая кнопки, некоторые из кнопок имеют только изображение для содержимого, другие имеют только текст. Я пытаюсь связать свойство ширины изображения кнопки с пользовательским свойством в моем производном классе ToolBar. Иногда это работает, но иногда выходит из строя со следующей ошибкой:
Ошибка System.Windows.Data: 4: Не удается найти источник для привязки со ссылкой 'RelativeSource FindAncestor, AncestorType =' NuiWpfCore.Controls.ToolBar ', AncestorLevel =' 1 ''. BindingExpression: Path = IconSize; DataItem = NULL; целевым элементом является "Изображение" (Name=''); Свойство target - "Ширина" (тип "Двойной")
Вот xaml, содержащий привязку элемента, которая терпит неудачу. DataTemplate возвращается из DataTemplateSelector, который создается встроенным:
<pres:ToolBar x:Class="NuiWpfCore.Controls.ToolBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:pres="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="clr-namespace:NuiWpfCore"
xmlns:ctrls="clr-namespace:NuiWpfCore.Controls"
xmlns:select="clr-namespace:NuiWpfCore.Selectors"
xmlns:converters="clr-namespace:NuiWpfCore.Converters"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase">
<ToolBar.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/NuiWpfCore;component/Controls/MenuBarTemplate.xaml" />
</ResourceDictionary.MergedDictionaries>
<converters:ListPairToStringConverter x:Key="ListPairToStringConverter" />
<converters:IconMetaDataToImageConverter x:Key="IconMetaDataToImageConverter" />
<converters:IconMetaDataToImageConverterParameter x:Key="IconToImageConverterParameter"
ConvertToImage="False" Width="16" Height="16" />
</ResourceDictionary>
</ToolBar.Resources>
<ToolBar.ItemTemplateSelector>
<select:ToolBarItemDataTemplateSelector>
<!-- other DataTemplates omitted for brevity -->
<select:ToolBarItemDataTemplateSelector.IconCommand>
<DataTemplate DataType="{x:Type core:PropertyElement}">
<Button IsEnabled="{Binding Path=CanEdit}" Command="{Binding}">
<Button.Content>
<Image
Width="{Binding Path=IconSize,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ctrls:ToolBar}} }"
Height="{Binding Path=Width,
RelativeSource={RelativeSource Self}}"
Source="{Binding Path=MetaData,
Converter={StaticResource IconMetaDataToImageConverter},
ConverterParameter={StaticResource IconToImageConverterParameter}}"/>
</Button.Content>
</Button>
</DataTemplate>
</select:ToolBarItemDataTemplateSelector.IconCommand>
<!-- other DataTemplates omitted for brevity -->
</select:ToolBarItemDataTemplateSelector>
</ToolBar.ItemTemplateSelector>
</pres:ToolBar>
Вот класс ToolBar со свойством Source для привязки.
public partial class ToolBar : System.Windows.Controls.ToolBar, Views.IView
{
public ToolBar() : base()
{
InitializeComponent();
IconSize = 32;
}
public int IconSize { get; set; }
}
Этот класс ToolBar иногда используется в ToolBarTray, а иногда нет, но в некоторых случаях поиск связывания завершается неудачей в обоих случаях.
У кого-нибудь есть идеи относительно того, почему это может быть неудачным?
2 ответа
DataTemplate выглядит так, как будто он определен в объявлении DataTemplateSelector, которое не является частью дерева визуалов, и поэтому не сможет перемещаться вверх оттуда, если привязка была оценена в этом месте. Где на самом деле применяется шаблон?
Рассматривали ли вы сделать IconSize
на вашей панели инструментов унаследованное свойство?
public static readonly DependencyProperty IconSizeProperty =
DependencyProperty.RegisterAttached( "IconSize", typeof(double), typeof(ToolBar ),
new FrameworkPropertyMetadata(32, FrameworkPropertyMetadataOptions.Inherits));
public static double GetIconSize(DependencyObject target)
{
return (double)target.GetValue(IconSizeProperty);
}
public static void SetIconSize(DependencyObject target, double value)
{
target.SetValue(IconSizeProperty, value);
}
Тогда вы можете просто получить доступ к IconSize, как
<Button.Content>
<Image
Width="{Binding RelativeSource={RelativeSource Self}, ctrls::ToolBar.IconSize}"
Height="{Binding Path=Width,RelativeSource={RelativeSource Self}}"
Source="{Binding Path=MetaData,
Converter={StaticResource IconMetaDataToImageConverter},
ConverterParameter={StaticResource IconToImageConverterParameter}}"/>
Сначала вы должны установить его на своей панели инструментов, и любой другой элемент в дереве может получить доступ к этому свойству.
Извините, я не уверен на 100%, чтобы быть правильным. Но общая идея Value Inheritance - хороший способ решить эту проблему.