WPF'de bir yönteme bağlanılsın mı?


90

WPF'de bu senaryoda bir nesne yöntemine nasıl bağlanırsınız?

public class RootObject
{
    public string Name { get; }

    public ObservableCollection<ChildObject> GetChildren() {...}
}

public class ChildObject
{
    public string Name { get; }
}

XAML:

<TreeView ItemsSource="some list of RootObjects">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type data:RootObject}" 
                                  ItemsSource="???">
            <TextBlock Text="{Binding Path=Name}" />
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type data:ChildObject}">
            <TextBlock Text="{Binding Path=Name}" />
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

Burada GetChildrenher bir RootObjectağaçtaki yönteme bağlanmak istiyorum .

DÜZENLEME bir bağlanma ObjectDataProviderBen bir öğe listesi için bağlayıcı olduğum için işe görünmüyor ve ObjectDataProviderihtiyaçları ya bir statik yöntem veya buna kendi örneği ve kullanımları işte yaratır.

Örneğin, Matt'in cevabını kullanarak şunu elde ederim:

System.Windows.Data Hatası: 33: ObjectDataProvider nesneyi oluşturamıyor; Tür = 'RootObject'; Hata = 'Yapıcı için yanlış parametreler.'

System.Windows.Data Hatası: 34: ObjectDataProvider: Tür üzerinde yöntemi çağırmaya çalışırken başarısızlık; Yöntem = 'GetChildren'; Tür = 'KökNesne'; Hata = 'Belirtilen üye hedefte çağrılamaz.' TargetException: 'System.Reflection.TargetException: Statik olmayan yöntem bir hedef gerektirir.


Evet, haklısın. ObjectDataProvider bir ObjectInstance özelliğine sahip (belirli bir örnekte yöntemini çağırmak için) ancak bunun bir bağımlılık özelliği olduğunu düşünmüyorum, bu yüzden onu bağlayamazsınız (AFAIK).
Matt Hamilton

1
Evet, ObjectInstance'a bağlanmaya çalıştım ve bunun bir bağımlılık özelliği olmadığını öğrendim.
Cameron MacFarland

Cevabımı yine de orada bırakacağım, hem güncellemenize biraz bağlam kazandırmak hem de bu soruyu yeterince benzer bir problemle bulan birine yardım etmek için.
Matt Hamilton

Aslında ObjectInstance'e bağlanmanız gerekiyor mu? (Değişecek mi) Bunun yerine kendi değişiklik-olay işlemenizi oluşturup kodda ObjectDataProvider'ı güncelleyebileceğinizi varsayarsak ...
Tim Lovell-Smith

1
Cevabımı bir yıl sonra bazı kaynak kodlarıyla güncelledim.
Drew Noakes

Yanıtlar:


71

İşinize yarayabilecek başka bir yaklaşım, IValueConverterbir yöntem adını parametre olarak alan bir özel oluşturmaktır , böylece aşağıdaki şekilde kullanılır:

ItemsSource="{Binding 
    Converter={StaticResource MethodToValueConverter},
    ConverterParameter='GetChildren'}"

Bu dönüştürücü, yansımayı kullanarak yöntemi bulur ve çağırır. Bu, yöntemin herhangi bir argümana sahip olmamasını gerektirir.

İşte böyle bir dönüştürücü kaynağına bir örnek:

public sealed class MethodToValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var methodName = parameter as string;
        if (value==null || methodName==null)
            return value;
        var methodInfo = value.GetType().GetMethod(methodName, new Type[0]);
        if (methodInfo==null)
            return value;
        return methodInfo.Invoke(value, new object[0]);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException("MethodToValueConverter can only be used for one way conversion.");
    }
}

Ve ilgili bir birim testi:

[Test]
public void Convert()
{
    var converter = new MethodToValueConverter();
    Assert.AreEqual("1234", converter.Convert(1234, typeof(string), "ToString", null));
    Assert.AreEqual("ABCD", converter.Convert(" ABCD ", typeof(string), "Trim", null));

    Assert.IsNull(converter.Convert(null, typeof(string), "ToString", null));

    Assert.AreEqual("Pineapple", converter.Convert("Pineapple", typeof(string), "InvalidMethodName", null));
}

Bu dönüştürücünün targetTypeparametreyi zorlamadığını unutmayın .


6
Hmmm, ... hile gibi görünüyor ama bunun tek yol olabileceğini düşünmeye başladım. Kesinlikle en kolayı olacak!
EightyOne Unite

25

Senaryonuzda ne kadar iyi çalışacağından emin değilsiniz, ancak verilerini almak için belirli bir yöntemi ( mülkünüzün belirli parametreleriyle ) çağırmasını sağlamak için MethodNameözelliği kullanabilirsiniz .ObjectDataProviderMethodParameters

İşte doğrudan MSDN sayfasından alınan bir pasaj:

<Window.Resources>
    <ObjectDataProvider ObjectType="{x:Type local:TemperatureScale}"
        MethodName="ConvertTemp" x:Key="convertTemp">
        <ObjectDataProvider.MethodParameters>
            <system:Double>0</system:Double>
            <local:TempType>Celsius</local:TempType>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

Yani bu , bir sınıfın örneğinde ObjectDataProviderbir ConvertTempyöntemi çağıran TemperatureScale, iki parametre ( 0ve TempType.Celsius) geçiren bir şeydir .


11

Yöntemi bağlamanız gerekiyor mu?

Yöntem alıcı olan bir mülke bağlanabilir misiniz?

public ObservableCollection<ChildObject> Children
{
   get
   {
      return GetChildren();
   }
}

2
Cameron'un yorumunu, mülk ekleyemeyeceği bir tip için bağlayıcı olduğu anlamına gelmek için alıyorum.
Drew Noakes

2
Yöntem potansiyel olarak uzun süre çalışıyorsa, özellikle yöntemleri çağıran özelliklere bağlanmaktan kaçınmalısınız. Bu tür yöntemlere sahip olmak iyi bir tasarım değildir, çünkü bir kod tüketicisi bir özelliğin yalnızca yerel bir değişkene erişmesini bekler.
markmnl

@markmnl yani doğrudan işleve bağlanmanın anlamı nedir? Yani OP'nin sorusu sizin davanız için mantıklı değil mi?
Teoman shipahi

4

Yöntemi çağırmak için bir özellik ekleyemediğiniz sürece (veya bu özelliği ekleyen bir sarmalayıcı sınıf oluşturmadığınız sürece) bildiğim tek yol bir ValueConverter kullanmaktır.


3

ObjectDataProvider ayrıca ObjectType yerine kullanılabilen bir ObjectInstance özelliğine sahiptir


3

System.ComponentModelBir tür için özellikleri dinamik olarak tanımlamak için kullanabilirsiniz (bunlar derlenmiş meta verilerin parçası değildirler). Alanlara bağlanmak mümkün olmadığından, değerlerini alanlarda depolayan bir türe bağlanmayı etkinleştirmek için WPF'de bu yaklaşımı kullandım.

ICustomTypeDescriptorVe TypeDescriptionProvidertürleri istediğini elde etmek için izin verebilir. Bu makaleye göre :

TypeDescriptionProviderbu sınıfı uygulayan ayrı bir sınıf yazmanıza ICustomTypeDescriptorve ardından diğer türler için tanımların sağlayıcısı olarak kaydetmenize olanak tanır .

Bu yaklaşımı kendim denemedim, ancak umarım sizin durumunuzda yardımcı olur.


0

WPF senaryonuzda bir nesnenin yöntemine bağlanmak için, temsilci döndüren bir özelliğe bağlanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.