2010-06-30 20 views
8

मेरे पास CollectionViewSource में संग्रहीत वस्तुओं का संग्रह है और DataGrid पर संग्रहीत है। मैं वर्तमान में DataGrid में चयनित ऑब्जेक्ट का 'विवरण दृश्य' प्रदर्शित करना चाहता हूं। मैं CollectionViewSource.View.CurrentItem का उपयोग कर वर्तमान ऑब्जेक्ट प्राप्त कर सकता हूं। के लिए उन गुणों में से प्रत्येक IsImportant विशेषता के साथ चिह्नितWPF: गतिशील रूप से किसी ऑब्जेक्ट की गुणों (कुछ) में किसी सूची को बाध्यकारी

MyClass 
{ 
    [IsImportant] 
    AProperty{} 

    AnotherProperty{} 

    [IsImportant] 
    YetAnotherProperty{} 
} 

मैं करना चाहते हैं क्या, एक लिस्टबॉक्स में प्रदर्शन एक लेबल (संपत्ति के नाम के साथ) और (संपादन के लिए) एक नियंत्रण है। बाइंडिंग को बनाए गए संपादन, डेटाग्रिड और बैकिंग ऑब्जेक्ट के बीच काम करना चाहिए। प्रदर्शित नियंत्रण संपत्ति के प्रकार के आधार पर भिन्न होना चाहिए, जो boolean, string या IEnumerable<string> हो सकता है (मैंने IValueConverter लिखा है ताकि गणना और नई लाइन-सीमांकित स्ट्रिंग के बीच परिवर्तित हो सके)।

क्या कोई इसे पूरा करने के लिए किसी विधि के बारे में जानता है? मैं वर्तमान में निम्नलिखित के माध्यम से एक संपत्ति के मूल्यों को प्रदर्शित कर सकते हैं, लेकिन संपादन उन्हें समर्थन वस्तु को अद्यतन नहीं होगा:

listBox.ItemsSource = from p in typeof(MyClass).GetProperties() 
         where p.IsDefined(typeof(IsImportant), false) 
         select p.GetValue(_collectionViewSource.View.CurrentItem, null); 

स्पष्ट करने के लिए, मैं ऐसा करने के लिए 'पूर्ण रूप से अपने' चाहते हैं, मैन्युअल रूप में संपत्ति के नाम निर्दिष्ट किए बिना एक्सएएमएल। यदि मैं रनटाइम पर XAML में गतिशील रूप से जोड़ सकता हूं, तो किस गुण के गुणों के साथ चिह्नित किया गया है, यह भी ठीक होगा।

उत्तर

12

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

public class PropertyValue 
{ 
    private PropertyInfo propertyInfo; 
    private object baseObject; 

    public PropertyValue(PropertyInfo propertyInfo, object baseObject) 
    { 
     this.propertyInfo = propertyInfo; 
     this.baseObject = baseObject; 
    } 

    public string Name { get { return propertyInfo.Name; } } 

    public Type PropertyType { get { return propertyInfo.PropertyType; } } 

    public object Value 
    { 
     get { return propertyInfo.GetValue(baseObject, null); } 
     set { propertyInfo.SetValue(baseObject, value, null); } 
    } 
} 

आपको इन नियंत्रणों के साथ पॉप्युलेट करने के लिए एक वस्तु को एक ListBox की ItemsSource बाँध, इसलिए एक IValueConverter कि अपनी महत्वपूर्ण गुणों के लिए PropertyValue वस्तुओं की एक सूची के लिए एक वस्तु में परिवर्तित कर देंगे बनाना चाहते हैं:

public class PropertyValueConverter 
    : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     return 
      from p in value.GetType().GetProperties() 
      where p.IsDefined(typeof(IsImportant), false) 
      select new PropertyValue(p, value); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     return Binding.DoNothing; 
    } 
} 

अंतिम चाल यह है कि आप संपादन नियंत्रण को संपत्ति के प्रकार के आधार पर बदलना चाहते हैं। आप ContentControl का उपयोग करके और सामग्री प्रकार के आधार पर सामग्री संपादक को विभिन्न संपादक टेम्पलेट्स में से एक पर सेट करके ऐसा कर सकते हैं। यह उदाहरण एक चेकबॉक्स का उपयोग करता है, तो संपत्ति एक बूलियन और नहीं तो किसी पाठ बॉक्स है:

<DataTemplate x:Key="CheckBoxTemplate"> 
    <CheckBox IsChecked="{Binding Value}"/> 
</DataTemplate> 
<DataTemplate x:Key="TextBoxTemplate"> 
    <TextBox Text="{Binding Value}"/> 
</DataTemplate> 
<Style x:Key="EditControlStyle" TargetType="ContentControl"> 
    <Setter Property="ContentTemplate" Value="{StaticResource TextBoxTemplate}"/> 
    <Style.Triggers> 
     <DataTrigger Binding="{Binding PropertyType}" Value="{x:Type sys:Boolean}"> 
      <Setter Property="ContentTemplate" Value="{StaticResource CheckBoxTemplate}"/> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 
<DataTemplate DataType="{x:Type local:PropertyValue}"> 
    <StackPanel Orientation="Horizontal"> 
     <Label Content="{Binding Name}"/> 
     <ContentControl Style="{StaticResource EditControlStyle}" Content="{Binding}"/> 
    </StackPanel> 
</DataTemplate> 

उसके बाद, आप सिर्फ अपने ListBox के रूप में बना सकते हैं:

<ItemsControl ItemsSource="{Binding Converter={StaticResource PropertyValueConverter}}"/> 
+0

कि शानदार लग रहा है; जैसे ही मुझे मौका मिलेगा, मैं इसे लागू कर दूंगा और आपको बता दूंगा कि यह कैसा चल रहा है। धन्यवाद! –

+0

यह अधिकतर काम करता है। मैंने अभी PropertyValueConverter पर एक नल चेक जोड़ा है, क्योंकि बाध्यकारी पहली बार सेट होने पर यह एक शून्य ऑब्जेक्ट प्राप्त कर रहा था। एकमात्र मुद्दा यह है कि वर्तमान में, यदि मैं इस नियंत्रण पर एक मूल्य बदलता हूं तो यह डेटाग्रिड के माध्यम से प्रचारित नहीं होता है। संभावित रूप से बैकिंग ऑब्जेक्ट बदल रहा है, क्योंकि बदले गए मान को अभी भी आइटम्स कंट्रोल द्वारा दिखाया गया है, लेकिन ग्रिड को अधिसूचित नहीं किया जा रहा है। क्या यह बाध्यकारी के साथ करना है। कुछ भी नहीं? –

+1

@Daniel: यदि आप एक ही संपत्ति द्वारा बनाए गए अपडेट चाहते हैं तो एक ही संपत्ति से जुड़े अन्य नियंत्रणों में प्रतिबिंबित होने के लिए आपके ऑब्जेक्ट को INotifyProperty को लागू करने की आवश्यकता होगी। आपको PropertyValue पर चेंज किए गए INotifyProperty को भी लागू करने की आवश्यकता होगी। PropertyValueConverter आइटम्ससोर्स के लिए बाध्यकारी है, जो एक तरफा है, इसलिए कनवर्टबैक नहीं कहा जाएगा और बाध्यकारी। कुछ भी कोई फर्क नहीं पड़ता। – Quartermeister

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