Мне лично не нравится идея установки DataContext
в элементах управления.Я думаю, что выполнение этого каким-то образом нарушит наследование контекста данных.Пожалуйста, посмотрите на этот пост .Я думаю, что Саймон объяснил это довольно хорошо.
По крайней мере, попробуйте удалить
DataContext="{Binding ElementName=myWindow}"
из
<tb:ToolBar Name="toolbar" DockPanel.Dock="Top" DataContext="{Binding ElementName=myWindow}>
и посмотрите, как это происходит.
ОБНОВЛЕНИЕ
Собственно, сохраните весь свой существующий код (на мгновение проигнорируйте мое предыдущее предложение), просто измените
<ComboBox ItemsSource="{Binding SomeProperty, ElementName=myWindow}">
на
<ComboBox ItemsSource="{Binding DataContext.SomeProperty}">
и посмотрите, работает ли он.
Я думаю, из-за того, как вы структурируете свои элементы управления, ComboBox
находится на том же уровне / уровне, что и tb:ToolBarControl
и tb:ToolBar
.Это означает, что все они используют один и тот же DataContext
, поэтому вам не требуется привязка ElementName
или RelativeSource
, чтобы попытаться найти своего родителя / предка.
Если вы удалите DataContext="{Binding ElementName=myWindow}
изtb:ToolBar
, вы даже можете избавиться от префикса DataContext
в привязке.И это действительно все, что вам нужно.
<ComboBox ItemsSource="{Binding SomeProperty}">
ОБНОВЛЕНИЕ 2 , чтобы ответить на ваш Изменить 3
Это потому, что ваша коллекция Items
в вашем tb:ToolBar
usercontrol это просто свойство.Это не в логическом и визуальном дереве, и я считаю, что ElementName
привязка использует логическое дерево.
Вот почему оно не работает.
Добавить в логическое дерево
Я думаю, чтобы добавить Items
в логическое дерево, вам нужно сделать две вещи.
Сначала вам нужно переопределить LogicalChildren
в вашем tb:ToolBar
пользовательском контроле.
protected override System.Collections.IEnumerator LogicalChildren
{
get
{
if (Items.Count == 0)
{
yield break;
}
foreach (var item in Items)
{
yield return item;
}
}
}
Тогда всякий раз, когда вы добавляете новый tb:ToolBarControl
, вам нужно позвонить
AddLogicalChild(item);
Дайте ему шанс.
Это РАБОТАЕТ ...
Немного поиграв с этим, я думаю, что того, что я показал вам выше, недостаточно.Вам также необходимо добавить эти ToolBarControls
в область имен вашего основного окна, чтобы включить привязку ElementName
.Я предполагаю, что именно так вы определили свойство зависимости Items
.
public static DependencyProperty ItemsProperty =
DependencyProperty.Register("Items",
typeof(ToolBarControlCollection),
typeof(ToolBar),
new FrameworkPropertyMetadata(new ToolBarControlCollection(), Callback));
В обратном вызове это место, где вы добавляете его в область имен.
private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var toolbar = (ToolBar)d;
var items = toolbar.Items;
foreach (var item in items)
{
// the panel that contains your ToolBar usercontrol, in the code that you provided it is a DockPanel
var panel = (Panel)toolbar.Parent;
// your main window
var window = panel.Parent;
// add this ToolBarControl to the main window's name scope
NameScope.SetNameScope(item, NameScope.GetNameScope(window));
// ** not needed if you only want ElementName binding **
// this enables bubbling (navigating up) in the visual tree
//toolbar.AddLogicalChild(item);
}
}
Также, если вы хотите наследовать свойства, вам потребуется
// ** not needed if you only want ElementName binding **
// this enables tunneling (navigating down) in the visual tree, e.g. property inheritance
//protected override System.Collections.IEnumerator LogicalChildren
//{
// get
// {
// if (Items.Count == 0)
// {
// yield break;
// }
// foreach (var item in Items)
// {
// yield return item;
// }
// }
//}
Я проверил код, и он отлично работает.