ผูกกับวิธีการใน WPF หรือไม่


90

คุณผูกกับเมธอดอ็อบเจ็กต์ในสถานการณ์นี้ใน WPF ได้อย่างไร

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>

ที่นี่ฉันต้องการผูกกับGetChildrenวิธีการบนRootObjectต้นไม้แต่ละต้น

แก้ไขการผูกกับ an ObjectDataProviderดูเหมือนจะไม่ได้ผลเพราะฉันเชื่อมโยงกับรายการของรายการและObjectDataProviderต้องการวิธีการแบบคงที่หรือสร้างอินสแตนซ์ของตัวเองและใช้สิ่งนั้น

ตัวอย่างเช่นการใช้คำตอบของ Matt ฉันได้รับ:

System.Windows.Data Error: 33: ObjectDataProvider ไม่สามารถสร้างวัตถุ พิมพ์ = 'RootObject'; ข้อผิดพลาด = 'พารามิเตอร์ไม่ถูกต้องสำหรับตัวสร้าง'

System.Windows.Data Error: 34: ObjectDataProvider: ความล้มเหลวในการพยายามเรียกใช้เมธอดในประเภท; วิธี = 'GetChildren'; พิมพ์ = 'RootObject'; ข้อผิดพลาด = 'ไม่สามารถเรียกสมาชิกที่ระบุในเป้าหมายได้' TargetException: 'System.Reflection.TargetException: วิธีการแบบไม่คงที่ต้องการเป้าหมาย


ถูกของคุณ. ObjectDataProvider มีคุณสมบัติ ObjectInstance (เพื่อเรียกใช้เมธอดบนอินสแตนซ์เฉพาะ) แต่ฉันไม่คิดว่ามันเป็นคุณสมบัติการพึ่งพาดังนั้นคุณจึงไม่สามารถผูกมันได้ (AFAIK)
Matt Hamilton

1
ใช่ฉันพยายามผูกกับ ObjectInstance และพบว่ามันไม่ใช่คุณสมบัติการพึ่งพา
Cameron MacFarland

ฉันจะทิ้งคำตอบไว้ที่นั่นทั้งเพื่อให้การอัปเดตของคุณมีบริบทและเพื่อช่วยคนอื่นที่พบคำถามนี้ที่มีปัญหาคล้ายกัน
Matt Hamilton

คุณจำเป็นต้องเชื่อมโยงกับ ObjectInstance หรือไม่? (จะเปลี่ยนไปไหม) สมมติว่าคุณสามารถสร้างการจัดการเหตุการณ์การเปลี่ยนแปลงของคุณเองแทนและอัปเดต ObjectDataProvider ในรหัส ...
Tim Lovell-Smith

1
เพิ่งอัปเดตคำตอบของฉันด้วยซอร์สโค้ดบางส่วนหนึ่งปีหลังจากข้อเท็จจริง
Drew Noakes

คำตอบ:


71

อีกวิธีหนึ่งที่อาจได้ผลสำหรับคุณคือการสร้างแบบกำหนดเองIValueConverterที่ใช้ชื่อเมธอดเป็นพารามิเตอร์เพื่อให้ใช้ในลักษณะนี้:

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

ตัวแปลงนี้จะค้นหาและเรียกใช้วิธีการโดยใช้การสะท้อน สิ่งนี้ต้องการให้เมธอดไม่มีข้อโต้แย้งใด ๆ

นี่คือตัวอย่างของแหล่งที่มาของตัวแปลงดังกล่าว:

และการทดสอบหน่วยที่เกี่ยวข้อง:

โปรดทราบว่าตัวแปลงนี้ไม่บังคับใช้targetTypeพารามิเตอร์


6
อืม ... ดูเหมือนแฮ็ค แต่ฉันเริ่มคิดว่านี่อาจเป็นวิธีเดียว แน่นอนว่าจะง่ายที่สุด!
EightyOne Unite

25

ไม่แน่ใจว่าจะทำงานได้ดีเพียงใดในสถานการณ์ของคุณ แต่คุณสามารถใช้MethodNameคุณสมบัติObjectDataProviderเพื่อเรียกวิธีการเฉพาะ (พร้อมพารามิเตอร์เฉพาะของMethodParametersคุณสมบัติของคุณ) เพื่อดึงข้อมูล

นี่คือตัวอย่างข้อมูลที่นำมาจากหน้า MSDN โดยตรง:

<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>

นั่นคือการObjectDataProviderเรียกConvertTempเมธอดบนอินสแตนซ์ของTemperatureScaleคลาสโดยส่งผ่านพารามิเตอร์สองตัว ( 0และTempType.Celsius)


11

ต้องผูกกับเมธอดไหม?

คุณสามารถผูกกับทรัพย์สินที่เป็นวิธีการได้หรือไม่?

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

2
ฉันใช้ความคิดเห็นของคาเมรอนเพื่อหมายความว่าเขามีผลผูกพันกับประเภทที่เขาไม่สามารถเพิ่มคุณสมบัติเข้าไปได้
Drew Noakes

2
คุณควรหลีกเลี่ยงการผูกมัดกับคุณสมบัติที่เรียกเมธอดโดยเฉพาะหากเมธอดนั้นอาจใช้งานได้นาน การมีวิธีการดังกล่าวคุณสมบัติจึงไม่ใช่การออกแบบที่ดีเนื่องจากผู้บริโภครหัสคาดว่าคุณสมบัติจะเข้าถึงเฉพาะตัวแปรในเครื่องเท่านั้น
markmnl

@markmnl แล้วจุดเชื่อมโยงโดยตรงกับฟังก์ชันคืออะไร? ดังนั้นคำถามของ OP จึงไม่สมเหตุสมผลกับกรณีของคุณ?
Teoman shipahi

4

เว้นแต่คุณจะสามารถเพิ่มคุณสมบัติเพื่อเรียกใช้เมธอด (หรือสร้างคลาส wrapper ที่เพิ่มคุณสมบัตินั้น) วิธีเดียวที่ฉันรู้คือใช้ ValueConverter



3

คุณสามารถใช้System.ComponentModelเพื่อกำหนดคุณสมบัติของประเภทแบบไดนามิก (ไม่ได้เป็นส่วนหนึ่งของข้อมูลเมตาที่คอมไพล์แล้ว) ฉันใช้แนวทางนี้ใน WPF เพื่อเปิดใช้งานการเชื่อมโยงกับชนิดที่เก็บค่าไว้ในฟิลด์เนื่องจากไม่สามารถเชื่อมโยงกับฟิลด์ได้

ICustomTypeDescriptorและTypeDescriptionProviderประเภทอาจช่วยให้คุณบรรลุสิ่งที่คุณต้องการ ตามบทความนี้ :

TypeDescriptionProviderช่วยให้คุณสามารถเขียนคลาสแยกต่างหากที่ใช้ICustomTypeDescriptorและจากนั้นลงทะเบียนคลาสนี้เป็นผู้ให้บริการคำอธิบายสำหรับประเภทอื่น ๆ

ฉันยังไม่ได้ลองใช้วิธีนี้ด้วยตัวเอง แต่หวังว่าจะเป็นประโยชน์ในกรณีของคุณ


0

เมื่อต้องการผูกกับเมธอดของอ็อบเจ็กต์ในสถานการณ์ WPF ของคุณคุณสามารถผูกกับคุณสมบัติที่ส่งคืนผู้รับมอบสิทธิ์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.