2012-02-25 17 views
6

का उपयोग कर प्रोग्राम उपयोगकर्ता को प्रोग्रामेटिक रूप से लोड करें मैं गतिशील रूप से किसी पृष्ठ पर वेब उपयोगकर्ता नियंत्रण जोड़ रहा हूं। LoadControl विधि का उपयोग करना जो केवल .ascx पर इंगित करने वाला वर्चुअल पथ लेता है, वह बहुत अच्छी तरह से काम करता है। हालांकि, LoadControl का अधिभार जो एक प्रकार और पैरामीटर की एक सरणी लेता है, मुझे कुछ सिरदर्द पैदा कर रहा है।लोडकंट्रोल (प्रकार, ऑब्जेक्ट())

वेब उपयोगकर्ता नियंत्रण अपेक्षित के रूप में तत्काल है, लेकिन वेब उपयोगकर्ता नियंत्रण में निहित नियंत्रण शून्य हैं और जैसे ही मैं उनके साथ काम करने की कोशिश करता हूं, मुझे अपवाद मिलता है। अजीब, क्योंकि यह LoadControl के पहले संस्करण का उपयोग करते समय काम कर रहा है।

वेब उपयोगकर्ता नियंत्रण, सरल, एक Literal नियंत्रण के साथ:

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="MyControl.ascx.vb" Inherits="MyControl" %> 
<asp:Literal ID="myLiteral" runat="server"></asp:Literal> 

नियंत्रण 'कोड के पीछे:

Public Class MyControl 
    Inherits System.Web.UI.UserControl 

    Public Property Data As MyData 

    Public Sub New() 

    End Sub 

    Public Sub New(data As MyData) 
    Me.Data = data 
    End Sub 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 
    myLiteral.Text = Data.ID ' The Literal is null, but ONLY when I use the second LoadControl() method! 
    End Sub 

End Class 

और .aspx से प्रासंगिक कोड है जहाँ से मैं कोशिश कर रहा हूँ गतिशील रूप से नियंत्रण लोड करें:

Private Sub Page_Init(sender As Object, e As System.EventArgs) Handles Me.Init 
    Dim x = LoadControl(GetType(MyControl), New Object() {New MyData With {.ID = 117}}) 
    Page.Controls.Add(x) 

    ' Using LoadControl("MyControl.ascx") works as expected! 
End Sub 

उत्तर

1
स्टीवन रॉबिंस द्वारा this article से मदद का एक सा के साथ

, मैं बजाय एक बहुत ही सुविधाजनक विस्तार विधि के साथ समाप्त हो गया:

Imports System.Runtime.CompilerServices 
Imports System.Web.UI 
Imports System.Reflection 

Module LoadControls 
    <Extension()> _ 
    Public Function LoadControl(templateControl As TemplateControl, virtualPath As String, ParamArray constructorParams() As Object) As UserControl 
    Dim control = TryCast(templateControl.LoadControl(virtualPath), UserControl) 
    Dim paramTypes = constructorParams.Select(Function(p) p.GetType()).ToArray 
    Dim constructor = control.GetType().BaseType.GetConstructor(paramTypes) 

    If constructor Is Nothing Then ' Nothing if no such constructor was found. 
     Throw New ArgumentException(String.Format("No constructor for control '{0}' with {1} parameter(s) were found.", virtualPath, paramTypes.Count)) 
    Else 
     constructor.Invoke(control, constructorParams) 
    End If 

    Return control 
    End Function 

End Module 
+1

ऐसा लगता है कि आप पहले से बनाए गए ऑब्जेक्ट पर एक कन्स्ट्रक्टर का आह्वान कर रहे हैं - यह कैसे काम करता है? – jmoreno

+0

@jmoreno चूंकि रचनाकार कुछ अतिरिक्त हबब के साथ केवल स्थिर तरीके हैं, यह सिर्फ काम करता है। –

+0

यहां एक त्वरित डेमो है: http://ideone.com/IoqU2Z (कोड अधिकांश ऑनलाइन संपादकों पर विफल रहता है क्योंकि इसे कुछ सुरक्षा मांग की आवश्यकता होती है, लेकिन यह पूर्ण विश्वास के साथ चलता है)। –

2

इस pos के अनुसार टी मैंने पाया: http://forums.asp.net/t/1375955.aspx, यह कहा गया था कि इसका उपयोग न करें।

पृष्ठ जो लोडरंट्रोल (प्रकार, ऑब्जेक्ट []) का उपयोग कर उपयोगकर्ता नियंत्रण को लोड करता है, वह अपने बच्चों को एसीएक्स फ़ाइल में नहीं जोड़ता प्रतीत होता है। पेज का उपयोग करना। लोड कंट्रोल (स्ट्रिंग) अपेक्षित के रूप में काम करता है।

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

यह साबित करने के लिए, बस MyControl में एक निजी संपत्ति को परिभाषित करें, और एसीएक्स पर मूल्य को बांधने का प्रयास करें, फिर आपको एक त्रुटि मिल जाएगी क्योंकि बाल वर्ग अपनी मूल कक्षा में किसी भी निजी चीज़ तक नहीं पहुंच सकता है।

0

जेकब, आप विस्तार कार्य के लिए बहुत बहुत धन्यवाद। यह बहुत आसान में आया है। हालांकि यह उन रचनाकारों के लिए जिम्मेदार नहीं है जो पैरामीटर द्वारा पैरामीटर लेते हैं।

मुझे यकीन है कि निम्नलिखित संशोधन को बहुत छोटा लिखा जा सकता है और GetConstructor तर्क को फिर से लिखने से बचें, लेकिन यह मैं कन्स्ट्रक्टर में ByRef पैरामीटर को संभालने के लिए आया था।

मैंने इसे सामान्य रखने की कोशिश की ताकि बाय्रफ को पैरामीटर की सेटिंग पैरामीटर इंडेक्स को हार्ड कोड किए जाने के बजाय मिलान करने वाले कन्स्ट्रक्टर पर आधारित हो।

संपादित करें: इस फ़ंक्शन का नकारात्मक हिस्सा है। आपके उपयोगकर्ता नियंत्रण के रचनाकारों को दो बार बुलाया जाता है। एक बार पहले लोडकंट्रोल द्वारा और फिर फिर जब दूसरा कन्स्ट्रक्टर पाया जाता है और पैरामीटर दिया जाता है। ध्यान रखें कि इसमें पेज_लोड भी दो बार चलता है। मैंने एक उप में वास्तविक पेज_लोड तर्क को समाहित किया है और इस मुद्दे से परहेज करते हुए दूसरा कन्स्ट्रक्टर इसे कॉल करता है।

Imports System.Runtime.CompilerServices 
Imports System.Web.UI 
Imports System.Reflection 

<Extension()> Public Function LoadControl(templateControl As TemplateControl, virtualPath As String, ParamArray constructorParams() As Object) As UserControl 
    Dim control As UserControl = TryCast(templateControl.LoadControl(virtualPath), UserControl) 
    Dim paramTypes() As Type = constructorParams.Select(Function(p) p.GetType()).ToArray 
    Dim isMatch As Boolean = True 

    ' ByRef Parameters 
    For Each cnst As ConstructorInfo In control.GetType.BaseType.GetConstructors 
     If cnst.GetParameters.Count = paramTypes.Count Then 
      Dim tempTypes(paramTypes.Count - 1) As Type 
      isMatch = True 
      Array.Copy(paramTypes, tempTypes, paramTypes.Length) 

      For i As Integer = 0 To paramTypes.Count - 1 
       If cnst.GetParameters(i).ParameterType.FullName.TrimEnd("&") = paramTypes(i).FullName Then 
        If cnst.GetParameters(i).ParameterType.IsByRef Then tempTypes(i) = paramTypes(i).MakeByRefType Else tempTypes(i) = paramTypes(i) 
       Else 
        isMatch = False 
       End If 
      Next 

      If isMatch Then 
       cnst.Invoke(control, constructorParams) 
       Exit For 
      End If 
     End If 
    Next 

    If not isMatch Then 
     Throw New ArgumentException(String.Format("No constructor for control '{0}' with {1} parameter(s) were found.", control, paramTypes.Count)) 
    End If 

    Return control 
End Function 
संबंधित मुद्दे