Самый прямой ответ
FindAncestor обрабатывается внутри WPF и выполняет поиск визуального дерева настолько далеко, насколько это возможно, прежде чем перейти куда-либо еще. Только когда он достигает Visual, который не имеет визуального родителя, он будет искать в другом месте, и это зависит от того, чего он достиг. Например, если он попадает в FrameworkContentElement, он может перейти в контейнер документа. К сожалению, если вершиной визуального дерева является ElementHost, он остановится, поэтому перенаправить вызов невозможно.
Это означает, что ваш самый простой вариант - заменить привязку. К счастью, это не очень сложно.
Как автоматически заменить привязку
Вот простой метод, который я написал некоторое время назад, который просматривает визуальное дерево и заменяет привязки, как указано в updateFunction. Если функция updateFunction возвращает привязку, отличную от переданной, привязка обновляется.
static void UpdateBindings(Visual visual, Func<Binding, Binding> updateFunction)
{
if(visual==null) return;
for(int i=0; i<VisualTreeHelper.GetChildrenCount(visual); i++)
UpdateBindings(VisualTreeHelper.GetChild(visual, i) as Visual, updateFunction);
for(var enumerator = visual.GetLocalValueEnumerator(); enumerator.MoveNext(); )
{
var property = enumerator.Current.Property;
var binding = BindingOperations.GetBinding(visual, property);
if(binding==null) continue;
var newBinding = updateFunction(binding);
if(newBinding!=binding)
BindingOperations.SetBinding(visual, property, newBinding);
}
}
Чтобы проиллюстрировать, как это работает, вот как вы можете написать метод, который заменяет определенный AncestorType во всех экземплярах RelativeSource FindAncestor, следующим образом:
static void ReplaceFindAncestorType(Visual visual, Type fromType, Type toType)
{
UpdateBindings(visual, binding =>
binding.RelativeSource.Mode != RelativeSourceMode.FindAncestor ? binding :
binding.RelativeSource.AncestorType != fromType ? binding :
new Binding
{
RelativeSource = new RelativeSource(
RelativeSourceMode.FindAncestor,
toType,
binding.RelativeSource.AncestorLevel),
Path = binding.Path,
Mode = binding.Mode,
Converter = binding.Converter,
StringFormat = binding.StringFormat,
UpdateSourceTrigger = binding.UpdateSourceTrigger,
});
}
Обратите внимание, что только новые часто используемые свойства копируются в новую привязку.
Метод ReplaceFindAncestorVisualType можно использовать примерно так:
elementHost.LayoutUpdated += (obj, e) =>
{
ReplaceFindAncestorType(elementHost, typeof(Window), typeof(ElementHost);
};
В вашем случае этот общий метод замены не будет работать: он будет искать свойство IsActive в вашем ElementHost, которого не существует. Поэтому вам, вероятно, нужно изменить больше, чем просто RelativeSource. Это означает, что ваш реальный код будет выглядеть примерно так:
elementHost.LayoutUpdated += (obj, e) =>
{
UpdateBindings(elementHost, binding =>
binding.RelativeSource.AncestorType != typeof(Window) ? binding :
new Binding
{
Source = ultimateContainingWindowOrOtherObjectHavingIsActiveProperty,
Path = new PropertyPath("IsActive"), // Put property name here
});
};
Обратите внимание, что в приведенном выше коде предполагается наличие любого FindAncestor: привязка окна - это та, которую мы ищем. Дополнительные условия могут быть добавлены по мере необходимости в условных.
Альтернативное решение
Существует еще одно, совершенно другое, доступное решение: можно фактически разместить контент в Окне без полей и добавить собственный код, чтобы это окно было расположено над ElementHost, чтобы оно находилось внутри другого окна. Это сложнее, чем кажется, поскольку вам приходится иметь дело с такими вещами, как ActiveWindow, ForegroundWindow, Z Order, минимизированное состояние, фокусировка клавиатуры и т. Д. Но если ваши потребности очень просты, это может быть разумным решением.