最直接的答案
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);
}
}
为了说明如何工作的,这里是你如何可以编写替换所有的RelativeSource FindAncestor实例特定AncestorType的方法,具体如下:
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);
};
你的情况,这个通用的替代技术是行不通的:它会找你的ElementHost的,一个isActive属性,它不存在。所以你可能需要改变的不仅仅是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,Minimized状态,键盘焦点等等。但是如果你的需求非常简单,这可能是一个合理的解决方案。
通过遍历树并使用'BindingOperations.GetBinding'获取绑定,然后更改绑定的RelativeSource属性,您是否可以在运行时获得Ribbon控件? – 2010-04-01 09:33:43
嗨Gp,我应该检索绑定的属性应该是什么..我不知道控件的哪个属性尝试绑定。 “目标属性是'NoTarget'GetBinding期望指定依赖项属性 – Pradeep 2010-04-01 14:31:52