Преобразователь вызывается, пока дерево визуалов все еще собирается, поэтому ваш Visual еще не является потомком окна.
Вы хотите выполнить преобразование, когда ваше визуальное дерево уже построено. Это делается путем регистрации обратного вызова Dispatcher с использованием Dispatcher.BeginInvoke(DispatcherPriority.Render, ...)
и выполнения вашей работы внутри обратного вызова.
Однако это нельзя использовать с преобразователем, поскольку преобразователь должен немедленно вернуть преобразованное значение. Простой обходной путь - использовать присоединенное свойство вместо конвертера. Вот как:
Предположим, ваша привязка выглядит следующим образом:
<SomeObject Abc="{Binding Xyz, Converter={x:Static my:Converter.Instance}}" />
Создание подкласса DependencyObject «Независимо от», содержащего вложенное свойство «AbcControl», у которого PropertyChangedCallback выполняет преобразование и изменяет свойство «Abc»:
public class AttachedProperties : DependencyObject
{
public Control GetAbcControl(...
public void SetAbcControl(...
... AbcControlProperty = RegisterAttached("AbcControl", typeof(Control), typeof(AttachedProperties), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var ctrl = (Control)e.NewValue;
Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
{
var win = Window.GetWindow(ctrl);
var transform = ctrl.TransformToAncestor(win); // Exception thrown here.
var pt = transform.Transform(new Point(0, 0));
obj.SetValue(AbcProperty, pt.Y);
});
}
});
}
Теперь вы можете написать:
<SomeObject AbcControl="{Binding Xyz}" />
Который установит для свойства Abc преобразованное значение Y.
Существует множество возможных вариантов этой общей идеи.