2010-05-05 14 views
5

मैं अपने आवेदन के लिए एक WPF उपयोगकर्ता नियंत्रण लिख रहा हूं, एक सूची बॉक्स और कुछ अन्य आइटम लपेट रहा हूं।मेरे Wpf UserControl के लिए DisplayMemberPath को कैसे कार्यान्वित करें?

ListBox एक नया ItemTemplate कि मेरी सूची में प्रत्येक आइटम के लिए जानकारी का चार टुकड़े प्रस्तुत करता है। मैं अपनी सूची वस्तुओं पर विशिष्ट गुणों के लिए चार बाइंडिंग में से प्रत्येक को हार्ड कोड कर सकता हूं और वे ठीक प्रदर्शित करते हैं।

हालांकि, मैं चाहता हूं कि मेरा UserControl थोड़ा अधिक लचीला हो।

ListBox और ComboBox पर वहाँ एक संपत्ति DisplayMemberPath (ItemsControl से विरासत में मिली) है कि "इंजेक्षन" करने के लिए उपयुक्त गुण मानक ItemTemplate में बाध्यकारी लगता है।

मैं अपने उपयोगकर्ता नियंत्रण के साथ एक ही परिणाम कैसे प्राप्त करते हैं?

मैं जानकारी प्रदर्शित की विन्यास अनुमति देने के लिए चार नई प्रॉपर्टी सेट अप करना चाहते हैं:

public string LabelDisplayPath { get; set; } 
public string MetricDisplayPath { get; set; } 
public string TitleDisplayPath { get; set; } 
public string SubtitleDisplayPath { get; set; } 

परावर्तक साथ ItemsControl.DisplayMemberPath की समीक्षा नीचे खरगोश की मांद में जाने के लिए लगता है, मैं नहीं कर पाए हैं यह कैसे काम करता है यह समझने के लिए।

इसके अलावा, अगर मैं पूरी तरह से पाठ्यक्रम बंद कर रहा हूँ - और वहाँ एक और है, और अधिक "WPF" तकनीक है कि मैं बजाय का उपयोग करना चाहिए है, कृपया मुझे उस दिशा में इशारा करते हैं।

अद्यतन

यहाँ मैं क्या हासिल करने की कोशिश कर रहा हूँ की एक स्पष्टीकरण है।

ListBox मेरे उपयोगकर्ता नियंत्रण प्रदर्शित करता है प्रति आइटम सूचना के चार टुकड़े के भीतर: लेबल, शीर्षक, उपशीर्षक और मीट्रिक

एक जगह में, मैं मुद्दों की एक सूची प्रदर्शित करने के लिए इस उपयोगकर्ता नियंत्रण का उपयोग करना चाहते हैं। हर अंक इस प्रकार है:

public class Issue { 
    public string Code { get; set; } 
    public string Description { get; set; } 
    public string Priority { get; set; } 
    public string Reporter { get; set; } 
} 

जब मुद्दों को प्रदर्शित करने, मैं निम्नलिखित मैपिंग का उपयोग करना चाहते:

Code --> Label 
Description --> Title 
Reporter --> Subtitle 
Priority --> Metric 

एक ही आवेदन में कहीं और, मुझे लगता है कि मैं का उपयोग कर प्रदर्शित करना चाहते हैं पदों की एक सूची है वही UserControl।

PostedOn --> Label 
Title --> Title 
Teaser --> Subtitle 
CommentCount --> Metric 

देखते हुए कि मुद्दे और पोस्ट काफी अलग कपोल-कल्पना कर रहे हैं, मैं नहीं चाहता कि उन्हें बाध्य करना चाहते हैं:

public class Post { 
    public DateTime PostedOn { get; set; } 
    public string Title { get; set; } 
    public string Teaser { get; set; } 
    public int CommentCount { get; set; } 
} 

पदों को प्रदर्शित करते हैं, मैं निम्नलिखित मैपिंग का उपयोग करना चाहते: प्रत्येक पोस्ट इस तरह दिखता है एक ही गुण रखने के लिए, केवल UserControl को अपरिवर्तित उपयोग करने की अनुमति देने के लिए। इसके बजाय, मैं एक छोटी कॉन्फ़िगरेशन शुरू करना चाहता हूं ताकि मैं दोनों साइट्स में अपने उपयोगकर्ता नियंत्रण को पुन: उपयोग कर सकूं।

+1

मुझे समझ में नहीं आता कि आप क्या करने की कोशिश कर रहे हैं। अपनी बाधाओं को "हार्डकोडिंग" करके, आप अभी भी केवल इस तथ्य से लचीलापन प्राप्त कर रहे हैं कि आप डेटाबेस का उपयोग कर रहे हैं, है ना? मेरा मतलब है, आप किसी भी निर्भरता प्रॉपर्टी से जुड़ सकते हैं और उस मान को कोड-पीछे में बदल सकते हैं। क्या आप एक्सएएमएल का एक नमूना पोस्ट कर सकते हैं जिसका उपयोग आप कर रहे हैं, और यह बताएं कि आप किससे नाखुश हैं? – Dave

उत्तर

2

मैं मेरी समस्या का हल मिल गया है -, यह थोड़ा और अधिक जटिल है की तुलना में मैं चाहता हूँ ...

किसी भी ItemsControl पर जब आप DisplayMemberPath गुण सेट, आंतरिक वर्ग का एक उदाहरण DisplayMemberTemplateSelector है ItemTemplateSelector को सौंपा गया।असल में, यह वर्ग DisplayMemberPath की वर्तमान कॉन्फ़िगरेशन के अनुरूप एक उचित बाध्यकारी के साथ एक कस्टम डेटा टेम्पलेट उत्पन्न करता है। इस वर्ग का एक नया उदाहरण बनाया गया है और हर बार DisplayMemberPath बदल दिया जाता है।

अपने स्वयं के उपयोगकर्ता नियंत्रण पर इसे दोहराने के लिए, मेरे मूल रूप से इच्छित फ्लाई पर मौजूदा डेटा टेम्पलेट को संशोधित करने के बजाय, मुझे अपना खुद का टेम्पलेट चयनकर्ता सहायक वर्ग बनाने और आइटम्सकंट्रोल के समान दृष्टिकोण की नकल करने की आवश्यकता है।

+0

मुझे यह बहुत समय पहले पता है, लेकिन क्या आपके पास कहीं भी सहायक उपलब्ध है? –

+0

अफसोस की बात है, मुझे अब उस कोड तक पहुंच नहीं है - यह पिछले नियोक्ता के लिए लिखा गया था। – Bevan

0

अपने अद्यतन और टिप्पणी से संकेत का एक बहुत बाद, मुझे लगता है कि आप प्राप्त कर सकते हैं कि का उपयोग कर DependencyProperty

मैं आपको विचार

XAML की रूपरेखा देता हूँ:

<UserControl x:Name="myControl"> 
    <StackPanel> 
     <TextBlock x:Name="textBlock" 
        Text="{Binding ElementName=myControl, Path=LabelDisplayPath}" /> 
     <TextBlock x:Name="textBlock" 
        Text="{Binding ElementName=myControl, Path=MetricDisplayPath}" /> 
     <TextBlock x:Name="textBlock" 
        Text="{Binding ElementName=myControl, Path=TitleDisplayPath}" /> 
     <TextBlock x:Name="textBlock" 
        Text="{Binding ElementName=myControl, Path=SubtitleDisplayPath}" /> 
    </StackPanel> 
</UserControl> 

जहां डिस्प्लेपैथ निर्भरता गुण हैं

अब पीछे UserControl कोड में इन निर्भरता गुण बनाएँ: LabelDisplayPathProperty, MetricDisplayPathProperty ...

अब आप उन्हें इस तरह इनबिल्ट DisplayMemberPath संपत्ति की तरह उपयोग कर सकते हैं:

<ListView ItemsSource="{Binding IssueList}"> 
    <ListView.ItemTemplate> 
     <DataTemplate> 
      <myUC:Control1 LabelDisplayPath = "{Binding Path=Issue.Code}" 
          MetricDisplayPath = "{Binding Path=Issue.Priority}" 
          TitleDisplayPath = "{Binding Path=Issue.Description}" 
          SubtitleDisplayPath = "{Binding Path=Issue.Reporter}" /> 
     </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 
0

मुझे लगता है कि आपका सर्वश्रेष्ठ दांव उपयोग करने के लिए है डेटा टेम्पलेट्स।
यदि आप इसे लचीला बनाना चाहते हैं, तो अपनी संसाधन लाइब्रेरी में एक डिफ़ॉल्ट डेटा टेम्पलेट को परिभाषित करें (आप इसे एक्स: कुंजी या एक्स: आइटम के लिए नाम परिभाषित नहीं कर सकते हैं)। प्रत्येक अलग-अलग वर्ग के लिए एक डेटा टेम्पलेट बनाएं जिसे आप प्रदर्शित करना चाहते हैं। तब बस बाँध/वर्गों के साथ अपनी सूची को भरने और वे मैं दो मामलों को एकजुट करने के इस मामले में रैपर के रूप में ViewModels का प्रयोग करेंगे डिफ़ॉल्ट डेटा टेम्पलेट :)

+1

ऐसा लगता है कि यह DRY सिद्धांत का उल्लंघन करता है (स्वयं को दोहराएं)। मैं प्रत्येक स्थिति के लिए एक अलग रूप और महसूस नहीं करना चाहता, मौजूदा टेम्पलेट के भीतर दिखाए गए सिर्फ अलग जानकारी। उपयोगकर्ता नियंत्रण के स्वरूप और अनुभव में किए गए किसी भी बदलाव को प्रत्येक (प्रत्येक) टेम्पलेट पर समान रूप से दोहराया जाना होगा। – Bevan

1

का उपयोग कर प्रदर्शित किया जाएगा: आप एक (सार) बना सकते हैं ItemViewModelBase कक्षा Label, Title, Subtitle, और Metric गुणों को परिभाषित करती है। फिर आप उसी आधार पर उन सभी वस्तुओं के लिए इस बेस वीएम से प्राप्त ठोस वर्ग बनाते हैं जिन्हें आप उसी नियंत्रण का उपयोग करके प्रदर्शित करना चाहते हैं। इनमें से प्रत्येक वर्ग गुणों में कुछ अलग करता है।
इस तरह, आप एकItemViewModelBase वर्ग के लिए DataTemplate परिभाषित कर सकते हैं, और यह दोनों आइटम प्रकार के लिए लागू कर दिया जाएगा।

कुछ कोड कर सकते हैं इस स्पष्ट:

public abstract class ItemViewModelBase 
{ 
    public abstract string Label { get; } 
    public abstract string Title { get; } 
    public abstract string Subtitle { get; } 
    public abstract string Metric { get; } 
} 

public class IssueViewModel : ItemViewModelBase 
{ 
    private Issue _issue; 

    public override string Label { get { return _issue.Code; } } 
    public override string Title { get { return _issue.Description; } } 
    public override string Subtitle { get { return _issue.Reporter; } } 
    public override string Metric { get { return _issue.Priority; } } 

    public IssueViewModel(Issue issue) 
    { 
     _issue = issue; 
    } 
} 

public class PostViewModel : ItemViewModelBase 
{ 
    private Post _post; 

    public override string Label { get { return _post.PostedOn.ToString(); } } 
    public override string Title { get { return _post.Title; } } 
    public override string Subtitle { get { return _post.Teaser; } } 
    public override string Metric { get { return _post.CommentCount.ToString(); } } 

    public PostViewModel(Issue post) 
    { 
     _post= post; 
    } 
} 

अपने ListBox में आप तो ItemViewModelBase उदाहरणों के बजाय Issue और Post उदाहरणों का एक संग्रह है, जो, एक आम DataTemplate का उपयोग कर रेंडर किया जाएगा की तरह प्रदर्शित करेगा इस:

<DataTemplate DataType="{x:Type local:ItemViewModelBase}"> 
    <StackPanel> 
     <TextBlock x:Name="txtLabel" Text="{Binding Label}"/> 
     <TextBlock x:Name="txtTitle" Text="{Binding Title}"/> 
     <TextBlock x:Name="txtSubtitle" Text="{Binding Subtitle}"/> 
     <TextBlock x:Name="txtMetric" Text="{Binding Metric}"/> 
    </StackPanel> 
</DataTemplate> 
बेशक

, अपने DataTemplate अलग ढंग से दिखाई देगा, ऊपर j है सिद्धांत का प्रदर्शन करने के लिए एक उदाहरण। इसके अलावा, आप गुणों के लिए अन्य रिटर्न प्रकारों को परिभाषित कर सकते हैं - मैंने उन्हें सभी तार बनाये हैं, हालांकि आपके पास DateTime और int आपके डेटा क्लास में हैं। एक और बात मैं उत्पादन कोड में नहीं करूँगा: DateTime.ToString(), जैसा कि मैंने PostViewModel.Label में किया था - इसे कुछ स्थानीयकृत स्ट्रिंग प्रस्तुति के साथ बेहतर रूप से बदलें।

+0

मैं इस प्रकार की विविधता का उपयोग कर सकता हूं - व्यक्तिगत 'समस्या', 'पोस्ट' और अन्य कक्षाओं को बनाए रखना, प्रत्येक को एडाप्टर के रूप में कस्टम रैपर में लपेटना। निम्नलिखित के लायक - धन्यवाद। – Bevan

+0

हां, यही वही है जो मैंने प्रस्तावित किया था। बस आप इसे रैपर/एडाप्टर कहते हैं और मैं इसे ViewModel कहते हैं। ;) – gehho

संबंधित मुद्दे