2009-03-25 14 views
20

मेरे पास एक परिदृश्य है जहां मुझे वास्तव में नहीं पता कि उपयोगकर्ता डेटा में एकाधिक नियंत्रणों को होस्ट करने के लिए डेटा को कैसे बाध्य करना है।डब्ल्यूपीएफ अलग-अलग डेटाकॉन्टेक्स के लिए एकाधिक नियंत्रण बाध्यकारी

डेटा मैं बाध्य करने के लिए चाहते हैं 2 वर्गों

UserInfo, UserExtendedInfo 

UserControl के DataContext UserInfo पर सेट है तो मैं आसानी से निम्नलिखित

<Label Name="LblEmail" Text="{Binding Email}" /> 

हालांकि मैं डॉन कर सबसे नियंत्रण बाध्य कर सकते हैं से आता है उपयोगकर्ताExtendedInfo वर्ग से आसानी से गुणों को बाध्य करने के बारे में नहीं पता। मेरा प्रारंभिक विचार प्रत्येक नियंत्रण के डेटाकॉन्टेक्स्ट को सेट करना था जो UserExtendedInfo से डेटा का उपयोग करना चाहता था, इसलिए मैं वही कर सकता था। लेकिन यह बोझिल लगता है क्योंकि मुझे मैन्युअल रूप से प्रत्येक व्यक्ति को मैन्युअल रूप से असाइन करना होगा। UserExtendedInfo के लिए डेटा प्रत्येक बार UserControl दिखाई देने पर डेटाबेस से प्राप्त किया जाना चाहिए ताकि यह सिंक से बाहर न हो।

XAML:

<Label Name="LblTest" Text="{Binding Locale}" /> 

पीछे कोड:

Private Sub UserManager_IsVisibleChanged(ByVal sender As System.Object, ByVal e As System.Windows.DependencyPropertyChangedEventArgs) 
     If DirectCast(e.NewValue, Boolean) Then 
      Dim user As UserInfo = DirectCast(DataContext, UserInfo) 

      If user IsNot Nothing Then 
       Dim usrExt As UserExtenedInfo = UserController.GetUserExtended(user.userID) 

       LblTest.DataContext = usrExt 
      Else 
       Throw New ArgumentException("UserId doesn't exist or is less than 1") 
      End If 
     End If 
    End Sub 

उत्तर

25

मैं शायद एक अलग वर्ग तो उप पैनल में डेटा की DataContext गुण स्थापित करने के लिए आपके उपयोगकर्ता वस्तु लपेटकर के बारे में सोचना होगा।

उदाहरण के लिए:

public class UserDataContext 
{ 
    public UserInfo UserInfo { get; set; } 
    public UserExtendedInfo UserExtendedInfo { get; set; } 
} 
तब में

अपने UserControl.xaml:

<!-- Binding for the UserControl should be set in its parent, but for clarity --> 
<UserControl DataContext="{Binding UserDataContext}"> 
    <StackPanel> 
    <Grid DataContext="{Binding UserInfo}"> 
     <TextBlock Text="{Binding Email}" /> 
    </Grid> 
    <Grid DataContext="{Binding UserExtendedInfo}"> 
     <TextBlock Text="{Binding Locale}" /> 
     <TextBlock Text="{Binding AboutMe}" /> 
    </Grid> 
    </StackPanel> 
</UserControl> 

मतलब यह है कि आपके UserInfo वर्ग ईमेल का एक गुण है

और

कि आपके UserExtendedInfo क्लास में है लोकेल और इसके बारे में

+0

ठीक है जो बहुत समझ में आता है। इतना नई सामग्री के बजाय एक नया मॉडल जिसका एकमात्र उद्देश्य इस विशेष दृश्य का समर्थन करने के, तो आप सिर्फ एक ViewModel जो आप देखना बाध्य कर सकते हैं की जनता के गुण के रूप में UserInfo और UserExtendedInfo जोड़ना चाहिए है बनाने के WPF में :) – Alex

+1

जानने के लिए। (रिच का देखें [उत्तर] (http://stackoverflow.com/questions/679933/wpf-binding-multiple-controls-to-different-datacontexts/680052#680052))। – totorocat

7

यह वह जगह है जहां एम-वी-वीएम बहुत आसान है। विचार (जैसा कि मैं इसे कम से कम समझता हूं ... अभी भी मेरे लिए बहुत नया) यह है कि खिड़की स्वयं "व्यूमोडेल" वर्ग से जुड़ी है। व्यूमोडेल क्लास सिर्फ एक वर्ग है जो सभी डेटा को इस तरह से प्रदर्शित करता है कि आपके पूरे पृष्ठ की सभी चीज़ों तक पहुंच हो ... यह केवल एक ही कक्षा में बांधने के लिए आपको आवश्यक सभी अलग-अलग वस्तुओं को एक साथ लाता है ... और आप इस वर्ग के उदाहरण के लिए विंडो (या पृष्ठ) का डेटाकॉन्टेक्स्ट सेट करते हैं। आपके UserInfo और UserInfoExtended उदाहरण ViewModel ऑब्जेक्ट के सार्वजनिक गुण हैं, और आप केवल उन बाध्यकारी तत्वों के पथ का उपयोग करते हैं जो आपको उचित ऑब्जेक्ट्स के उपयुक्त गुणों के माध्यम से प्राप्त करने के लिए करते हैं जिन्हें आप प्रत्येक नियंत्रण को बांधना चाहते हैं।

इस पैटर्न को समझाते हुए एक शानदार (लेकिन काफी लंबा) वीडियो है, और यह एक पूर्ण उदाहरण के माध्यम से जाता है जो इसे पूरा करने के कई तरीकों को दिखाता है और यह कई अलग-अलग कारण बताता है कि यह एक WPF ऐप में उपयोग करने के लिए सुविधाजनक और स्केलेबल मॉडल क्यों है। इसमें डब्ल्यूपीएफ की कई विशेषताओं के साथ-साथ निर्भरता इंजेक्शन की शुरुआत भी शामिल है, जो उदाहरण के साथ-साथ बहुत प्रासंगिक विषय भी हैं।

संपादित: ब्लॉग पोस्ट हटा दिया गया है (इस जवाब काफी पुराना है)

यहाँ ब्लॉग पोस्ट जो वीडियो मैं की बात कर रहा हूँ करने के लिए एक लिंक होता है के लिए एक लिंक है।

https://www.youtube.com/watch?v=BRxnZahCPFQ

+0

सिर्फ एक नोट, ViewModel निर्भरता गुणों की आवश्यकता नहीं है। यदि आप नियंत्रणों को अपनी संपत्तियों में से किसी एक में परिवर्तन को प्रतिबिंबित करना चाहते हैं तो इसे केवल INotifyProperty को लागू करने की आवश्यकता है। –

+0

लिंक मर चुका है, क्या आप लिंक को अपडेट करेंगे? –

+0

@HassanTareq यूट्यूब पर यह मिला और लिंक – Rich

6

दोनों अमीर और bendewey अच्छा जवाब था: यहाँ यूट्यूब पर वीडियो है। WPF के बजाय आज सिल्वरलाइट में इसी विषय की खोज करते हुए, मैंने पाया कि एकाधिक डेटाकॉन्टेक्स स्थापित करना आवश्यक नहीं है। bendewey के उदाहरण संशोधन:

<UserControl DataContext="{Binding UserDataContext}"> 
    <StackPanel> 
     <TextBlock Text="{Binding Path=UserInfo.Email}" /> 
     <TextBlock Text="{Binding Path=UserExtendedInfo.Locale}" /> 
     <TextBlock Text="{Binding Path=UserExtendedInfo.AboutMe}" /> 
    </StackPanel> 
</UserControl> 

बाध्यकारी पथ का उपयोग करके आप नियंत्रण 'कंटेनरों के DataContext के लिए चिंता का विषय बिना लचीलापन मिश्रण करने और विभिन्न वर्गों के गुणों के मैच बाइंडिंग प्राप्त करें।

आप उपयोगकर्ता इन्फॉर्मेशन और UserExtendedInfo कक्षाओं के गुणों को कुशल बनाने वाले गुणों को जोड़कर बेंडवे के UserDataContext क्लास की क्षमताओं को भी बढ़ा सकते हैं। उदाहरण के लिए, आप पहले नाम और अंतिम नाम को जोड़ सकते हैं।

आप INotifyPropertyChanged को कार्यान्वित करना चाहते हैं ताकि जब आप UserInfo और UserExtendedInfo को रीसेट करते हैं तो आपके नियंत्रण अपडेट होते हैं।

यह उपयोगकर्ता डेटाटाटाटेक्स्ट में सीधे आवश्यक गुणों को उजागर करके XAML से अंतर्निहित UserInfo और UserExtendedInfo कक्षाओं को पूरी तरह से अलग करने के लिए आर्किटेक्चररी रूप से बेहतर हो सकता है, जिससे बाध्यकारी पथ की आवश्यकता समाप्त हो जाती है।

+1

अद्यतन इस bendeway के जवाब (+1) पर एक सुधार है, लेकिन मैं कुछ और कार्य में सुधार होगा: आप "पथ =" की जरूरत नहीं है, और 95% मामलों में मैं एक स्पष्ट वर्ग के बजाय सी # अज्ञात प्रकार का उपयोग करेगा। –

15

यहाँ सब का सबसे सरल तरीका है, और यह बहुत अच्छी तरह से काम करता है।

में कोड-पीछे जहां संदर्भ निर्धारित करते हैं, बस सभी वांछित मूल्यों से युक्त एक गुमनाम प्रकार का उपयोग करें:

DataContext = new 
{ 
    info = FetchUserInfoFromDatabase(), 
    extendedInfo = FetchExtendedUserInfoFromDatabase(), 
}; 

XAML में आप कुछ भी करने के लिए बाध्य कर सकते हैं:

<UserControl> 
    <StackPanel> 
    <TextBlock Text="{Binding info.Email}" /> 
    <TextBlock Text="{Binding extendedInfo.Locale} /> 
    ... 

वैकल्पिक रूप से आप दो स्तरों में बाध्य कर सकते हैं क्योंकि अन्य उत्तरों ने वर्णन किया है:

<UserControl> 
    <StackPanel> 
    <Grid DataContext="{Binding info}"> 
     <TextBlock Text={Binding Email}"> 
     ... 
+0

धन्यवाद! एक टन बाहर मेरी मदद की! –

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