The most direct answer
FindAncestor is processed internally by WPF and will search up the visual tree as far as it can before going anywhere else. Only when it reaches a Visual that has no visual parent will it search elsewhere, and this depends on what it reached. For example, if it hits a FrameworkContentElement it can go to the document's container. Unfortunately if the top of the visual tree is a ElementHost, it will stop, so there is no way to reroute the call.
This means that your simplest option is to replace the binding. Fortunately this is not very difficult.
How to automatically replace a binding
Here is a simple method I wrote a while back that searches through a visual tree and replaces bindings as directed by an updateFunction. If the updateFunction returns a different binding than it is passed, the binding is updated.
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);
}
}
To illustrate how this works, here is how you could write a method that replaces a specific AncestorType in all RelativeSource FindAncestor instances, as follows:
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,
});
}
Note that only commonly-used properties are copied over to the new binding.
The ReplaceFindAncestorVisualType method could be used something like this:
elementHost.LayoutUpdated += (obj, e) =>
{
ReplaceFindAncestorType(elementHost, typeof(Window), typeof(ElementHost);
};
In your case this generic replace technique won't work: It will be looking for an IsActive property on your ElementHost, which does not exist. So you probably need to change more than just the RelativeSource. This means your actual code will be more like this:
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
});
};
Note that the above code assumes any FindAncestor:Window binding is the one we are looking for. More conditions can be added as needed in the conditional.
Alternative solution
There is another, completely different, solution available: It is possible to actually host the content in a borderless Window and add custom code to keep this window positioned over the ElementHost so it appears to be within the other window. This is trickier than it sounds since you have to deal with things such as ActiveWindow, ForegroundWindow, Z Order, Minimized state, keyboard focus, etc. But if your needs are very simple this can be a reasonable solution.