2010-05-14 14 views
6

Pencerenin üst kısmına göre bir denetimin ofsetini almaya çalışıyorum, ancak kontrolün TransformToAncestor yöntemini kullanırken sorun yaşıyorum. Not: Bu kod, bir kontrolden pencereye göreceli olarak ilgili Y pozisyonuna dönüşecek bir değer dönüştürücüsündedir.TransformToAncestor kullanırken hata: "Belirtilen Görsel bu Görsel'in atası değildir."

public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
{ 
    var ctrl = (Control) value; 
    var win = Window.GetWindow(ctrl); 
    var transform = ctrl.TransformToAncestor(win); // Exception thrown here. 
    var pt = transform.Transform(new Point(0, 0)); 
    return pt.Y; 
} 

Window.GetWindow çalışmalara çağrı gayet güzel ve doğru pencere nesnesi içindeki denetimin bulunduğu döndürür.

WPF'nin bir "atası" olarak ne düşündüğünü yanlış anladım mı? GetWindow sonucuna göre, bu pencerenin kontrolün atası olacağını düşünürdüm. Ataların soyunun belirli bir noktada kesilmesine neden olabilecek belirli yuvalama paternleri var mı?

GÜNCELLEME: Bu bir zamanlama sorunu olabilir gibi

görünüyor. TransformToAncestor yöntemini, değer dönüştürücüsünden ziyade bir olay işleyicisine çağırmayı denediğimde, yalnızca iyi çalıştı. Atalara ait ilişki kurulmadan önce belirli unsurlar ortaya çıktıkça, değer dönüştürücünün çalıştığı anlaşılmaktadır.

MVVM desenini kullanmaya çalıştığımdan (ve bu nedenle gerçekten olay işleyicilerini kullanmak istemediğimden ve ViewModel öğesinde System.Windows öğelerinin olmasını istemediğinden) bu konuda nasıl emin olacağımı bilmiyorum.

cevap

8

Görsel ağaç hala bir araya getirilirken dönüştürücü çağrılıyor, bu nedenle Görseliniz henüz Pencerenin bir soyundan değil.

Görsel ağacınız zaten oluşturulduğunda dönüştürmeyi yapmak istiyorsunuz. Bu, Dispatcher.BeginInvoke(DispatcherPriority.Render, ...) kullanarak bir Dispatcher geri arama kaydettirmek ve işinizi geri arama içinde yapmakla yapılır.

Bu, dönüştürücüyle birlikte kullanılamaz, çünkü dönüştürücü hemen dönüştürülen değeri döndürmelidir. Basit bir çözüm, dönüştürücü yerine ekli bir özellik kullanmaktır. İşte nasıl: kimin PropertyChangedCallback dönüşüm yapar ve "Abc" özelliğini değiştirir,

<SomeObject Abc="{Binding Xyz, Converter={x:Static my:Converter.Instance}}" /> 

bir DependencyObject alt sınıfı "ne olursa olsun" içeren ekli bir özelliği "AbcControl" oluşturun:: senin bağlayıcı varsayalım

böyledir

Şimdi
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); 
     }); 
    } 
    }); 
} 

yazabilirsiniz:

<SomeObject AbcControl="{Binding Xyz}" /> 

Abc özelliğini dönüştürülmüş Y değerine ayarlayacaktır.

Bu genel fikir üzerinde birçok varyasyon mümkündür.

İlgili konular