समस्या:
"मुझे इस तरह एक कारखाने जानता है कि डेटा ग्रिड के लिए वस्तुओं को बनाने के लिए कैसे रजिस्टर करने के लिए तलाश कर रहा हूँ" । अगर हम DataGrid.CanUserAddRows = true
सेट
और फिर डेटा ग्रिड के लिए आइटम का संग्रह बाँध जहां आइटम एक डिफ़ॉल्ट नहीं है: (व्यापार वस्तुओं की मेरे संग्रह एक डिफ़ॉल्ट निर्माता प्रदान क्योंकि यह नहीं है।)
लक्षण कन्स्ट्रक्टर, फिर डेटाग्रिड 'नई आइटम पंक्ति' नहीं दिखाता है।
कारणों:
एक BindingListCollectionView जब संग्रह के लिए बाध्य किया जा रहा एक BindingList<T>
है:
जब आइटम का संग्रह किसी भी WPF ItemControl के लिए बाध्य है, WPF में या तो संग्रह गिर्द घूमती है। BindingListCollectionView
IEditableCollectionView लागू करता है लेकिन IEditableCollectionViewAddNewItem
लागू नहीं करता है।
ListCollectionView संग्रह संग्रह होने पर कोई अन्य संग्रह है। ListCollectionView
लागू IEditableCollectionViewAddNewItem (और इसलिए IEditableCollectionView
)।
विकल्प के लिए 2) डेटाग्रिड ListCollectionView
पर नए आइटम का निर्माण करता है। ListCollectionView
आंतरिक रूप से एक डिफ़ॉल्ट कन्स्ट्रक्टर के अस्तित्व के लिए परीक्षण करता है और यदि कोई अस्तित्व में नहीं है तो AddNew
अक्षम करता है। DotPeek का उपयोग करके ListCollectionView से प्रासंगिक कोड यहां दिया गया है।
public bool CanAddNewItem (method from IEditableCollectionView)
{
get
{
if (!this.IsEditingItem)
return !this.SourceList.IsFixedSize;
else
return false;
}
}
bool CanConstructItem
{
private get
{
if (!this._isItemConstructorValid)
this.EnsureItemConstructor();
return this._itemConstructor != (ConstructorInfo) null;
}
}
इस व्यवहार को ओवरराइड करने का एक आसान तरीका प्रतीत नहीं होता है।
विकल्प के लिए 1) स्थिति बहुत बेहतर है। डेटाग्रिड बाध्यकारी लिस्ट व्यू में नए आइटम बनाने का प्रतिनिधि है, जो बदले में BindingList पर प्रतिनिधि है। BindingList<T>
एक डिफ़ॉल्ट कन्स्ट्रक्टर के अस्तित्व के लिए भी जांच करता है, लेकिन सौभाग्य से BindingList<T>
क्लाइंट को AllowNew प्रॉपर्टी सेट करने और एक नई आइटम की आपूर्ति के लिए इवेंट हैंडलर संलग्न करने की अनुमति देता है।समाधान बाद में मिलेंगे, लेकिन यहां BindingList<T>
public bool AllowNew
{
get
{
if (this.userSetAllowNew || this.allowNew)
return this.allowNew;
else
return this.AddingNewHandled;
}
set
{
bool allowNew = this.AllowNew;
this.userSetAllowNew = true;
this.allowNew = value;
if (allowNew == value)
return;
this.FireListChanged(ListChangedType.Reset, -1);
}
}
गैर समाधान में प्रासंगिक कोड है: डेटा ग्रिड (उपलब्ध नहीं) द्वारा
यह उम्मीद करना उचित होगा डेटाग्रिड क्लाइंट को कॉलबैक संलग्न करने की अनुमति देने के लिए, जिसके माध्यम से डेटाग्रिड एक डिफ़ॉल्ट नए आइटम का अनुरोध करेगा, जैसे ऊपर BindingList<T>
। जब ग्राहक की आवश्यकता होती है तो यह क्लाइंट को एक नया आइटम बनाने पर पहली दरार देगा।
दुर्भाग्यवश यह डेटाग्रिड से सीधे समर्थित नहीं है, यहां तक कि .NET 4.5 में भी।
.NET 4.5 में एक नया ईवेंट 'AddingNewItem' प्रतीत होता है जो पहले उपलब्ध नहीं था, लेकिन यह केवल आपको एक नया आइटम जोड़ने के बारे में बताता है।
काम arounds:
- व्यापार वस्तु एक ही विधानसभा में एक उपकरण के द्वारा बनाई गई: का प्रयोग कर एक आंशिक वर्ग
इस परिदृश्य बहुत संभावना नहीं लगता है, लेकिन कल्पना कीजिए कि इकाई की रूपरेखा अपनी इकाई वर्गों बनाया बिना किसी डिफॉल्ट कन्स्ट्रक्टर (संभवतः वे serializable नहीं होंगे) के साथ, तो हम केवल एक डिफ़ॉल्ट कन्स्ट्रक्टर के साथ आंशिक वर्ग बना सकते हैं। समस्या सुलझ गयी।
- व्यापार वस्तु किसी अन्य असेंबली में है, और मुहरबंद नहीं है: व्यवसाय प्रकार का एक सुपर-प्रकार बनाएं।
यहां हम व्यवसाय ऑब्जेक्ट प्रकार से प्राप्त कर सकते हैं और एक डिफ़ॉल्ट कन्स्ट्रक्टर जोड़ सकते हैं।
यह शुरुआत में एक अच्छा विचार की तरह लग रहा था, लेकिन दूसरे विचारों पर इसे आवश्यकतानुसार अधिक काम की आवश्यकता हो सकती है क्योंकि हमें व्यवसाय परत द्वारा उत्पादित डेटा को हमारे ऑब्जेक्ट के सुपर-टाइप संस्करण में कॉपी करने की आवश्यकता है।
हम जैसे
class MyBusinessObject : BusinessObject
{
public MyBusinessObject(BusinessObject bo){ ... copy properties of bo }
public MyBusinessObject(){}
}
कोड की आवश्यकता होगी और फिर कुछ LINQ इन वस्तुओं में से सूचियों के बीच परियोजना के लिए।
- व्यापार वस्तु किसी अन्य असेंबली में है, और सील कर दी गई है (या नहीं): व्यापार वस्तु को समाहित करें।
यह बहुत आसान
class MyBusinessObject
{
public BusinessObject{ get; private set; }
public MyBusinessObject(BusinessObject bo){ BusinessObject = bo; }
public MyBusinessObject(){}
}
अब सब हम क्या करने की जरूरत कुछ LINQ का उपयोग इन वस्तुओं में से सूचियों के बीच परियोजना के लिए, और फिर डेटा ग्रिड में MyBusinessObject.BusinessObject
करने के लिए बाध्य है। गुणों की कोई गन्दा लपेटना या मूल्यों की प्रतिलिपि बनाना आवश्यक नहीं है।
समाधान: उपयोग BindingList<T>
(हुर्रे एक मिला)
आपके महान उत्तर के लिए धन्यवाद। ListCollectionView क्लास IEDitableCollectionViewAddNewItem इंटरफ़ेस लागू करता है। मैंने परावर्तक के माध्यम से कार्यान्वयन पर एक नज़र डाली थी।माइक्रोसॉफ्ट ने इस कक्षा में बहुत सारे प्रदर्शन अनुकूलन किए। मैं फैक्ट्री विधि का उपयोग करने के लिए अपने लिए इस इंटरफेस को लागू नहीं करना चाहता हूं। – jbe
@jbe। मैं समझता हूं कि :) इसके अलावा, IEDitableCollectionViewAddNewItem पर बहुत सारी जानकारी नहीं थी, कम से कम यह नहीं कि मैं ढूंढ पाया। यदि आप अपना कार्य पूरा करने का कोई तरीका ढूंढते हैं तो अपडेट करना सुनिश्चित करें –