Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: VB.NET: VB.Net, Usercontrol, DataGridView

Sivun loppuun

ari kood [15.09.2017 08:58:17]

#

Moi,

Tein usercontrollin jossa datagridview, mutta en pysty muokkaamaan dgv:n sarakkeita design tilassa.

Löysin tämän ohjeen ja käänsin sen vb:lle, mutta kun klikkaan designerissä usercontrollin Columns propertyä, saan virheilmoituksen : "object reference not set to an instance of an object".

Tässä vb koodi.

Imports System.ComponentModel
Imports System.Drawing.Design

Public Class uc_test

    <Editor(GetType(MyColumnEditor), GetType(UITypeEditor))>
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
    Public ReadOnly Property Columns As DataGridViewColumnCollection
        Get
            Return Me.DataGridView1.Columns
        End Get

    End Property

End Class
Public Class MyColumnEditor
    Inherits UITypeEditor

    Public Overrides Function GetEditStyle(context As ITypeDescriptorContext) As UITypeEditorEditStyle
        Return UITypeEditorEditStyle.Modal
    End Function

    Public Overrides Function EditValue(context As ITypeDescriptorContext, provider As IServiceProvider, value As Object) As Object
        'Return MyBase.EditValue(context, provider, value)

        Dim field = context.Instance.GetType().GetField("datagridview1",
                                                        System.Reflection.BindingFlags.NonPublic Or
                                                        System.Reflection.BindingFlags.Instance)
        Dim datagridview1 = DirectCast(field.GetValue(context.Instance), DataGridView)
        datagridview1.Site = DirectCast(context.Instance, Control).Site
        Dim columnsProperty = TypeDescriptor.GetProperties(datagridview1)("Columns")
        Dim tdc = New TypeDescriptionContext(datagridview1, columnsProperty)
        Dim editor = DirectCast(columnsProperty.GetEditor(GetType(UITypeEditor)), UITypeEditor)
        Dim result = editor.EditValue(tdc, provider, value)
        datagridview1.Site = Nothing
        Return result

    End Function

End Class
Public Class TypeDescriptionContext
    Implements ITypeDescriptorContext


    Private EditingObject As Control
    Private EditingProperty As PropertyDescriptor

    Public Sub New(ByVal obj As Control, ByVal prop As PropertyDescriptor)
        EditingObject = obj
        EditingProperty = prop

    End Sub


    Public ReadOnly Property Container As IContainer Implements ITypeDescriptorContext.Container
        Get
            Return EditingObject.Container
        End Get
    End Property

    Public ReadOnly Property Instance As Object Implements ITypeDescriptorContext.Instance
        Get
            Return EditingObject
        End Get
    End Property

    Public ReadOnly Property PropertyDescriptor As PropertyDescriptor Implements ITypeDescriptorContext.PropertyDescriptor
        Get
            Return EditingProperty
        End Get
    End Property

    Public Sub OnComponentChanged() Implements ITypeDescriptorContext.OnComponentChanged

    End Sub

    Public Function GetService(serviceType As Type) As Object Implements IServiceProvider.GetService
        Return EditingObject.Site.GetService(serviceType)
    End Function

    Public Function OnComponentChanging() As Boolean Implements ITypeDescriptorContext.OnComponentChanging
        Return True
    End Function
End Class

Onko koodissa jokin virhe, vai mikä maksaa..?

groovyb [15.09.2017 09:50:36]

#

Virheilmoituksessa kerrotaan myös millä rivillä virhe tapahtuu (Stack trace). Koita myös debugata, itse virhe tulee siitä että käytät esimerkiksi objektin propertyä, objektin ollessa null.

ari kood [17.09.2017 09:52:13]

#

Virheilmoitus tulee siis designerissä kun klikkaan usercontrollin columns-propertyä.

Kesti hetken kun selvitin miten design-time koodia debugataan. Jos jotain kiinnostaa niin tuolta löytyy esimerkki.

No, debuggauksessa kuitenkin selvisi, että virhe tulee riviltä:

Dim datagridview1 = DirectCast(field.GetValue(context.Instance), DataGridView)

,koska edellisellä rivillä luotu field = nothing

Dim field = context.Instance.GetType().GetField("datagridview1",
                                                        System.Reflection.BindingFlags.NonPublic Or
                                                        System.Reflection.BindingFlags.Instance)

Miksi field = nothing...? sitä en ymmärrä.(enkä kovin paljon muutakaan tuosta koodista)

groovyb [17.09.2017 10:35:09]

#

Lähde purkamaan debugilla tuota context.instancea, ja selvitä löytyykö sieltä mitään. Eli oletko esimerkiksi nimennyt datagridview componenttisi muulla nimellä kuin datagridview1.

ari kood [18.09.2017 13:18:29]

#

Ei onnistu. yritin, mutta en ymmärrä puoliakaan mitä tuossa pitäisi tapahtua.

Voisitko Groovyb(tai joku muu) kokeilla tuota omalla koneella. (Tai ehkäpä jo tiedät miksei tuo toimi.)

Vai onko kenties muita keinoja muokata usercontrollin dgv:n sarakkeita formilla design aikana (siten, että muutokset pysyisivät myös ajon aikana)?

groovyb [18.09.2017 23:41:56]

#

Kun laitat breakpointin field -riville, ja watchiin vaikka tuo context.Instance.GetType(), mitä palautuu? Palautuuko mitään?
Eli missä vaiheessa null reference on - context? .Instance? .GetType()? jne

ari kood [19.09.2017 09:20:48]

#

HAHAA! Keksin sen!
Usercontrol luokkaan pitää laittaa property joka palauttaa kyseisen dgv:n ja sitten MyColumnsEditoriin .GetField sijaan .GetProperty.

Tämä kylläkin aiheuttaa taas uuden ongelman

josta Harald Coppoolse mainitsi keskustelussa josta koodin lainasin kirjoitti:

Checked it, and it works. Be aware though that the columns that you add during design are added as members to the form, not to the user control. Luckily I don't need them in this situation. So I can set GenerateMember to false

En osaa nyt sanoa auttaako tuo GenerateMember=false minua, mutta.. .mihin laitan/mistä muutan tuon GenerateMemberin?

Quirzo [19.09.2017 09:35:52]

#

ari kood kirjoitti:

(19.09.2017 09:20:48): HAHAA! Keksin sen! Usercontrol luokkaan...

Muistaakseni GenerateMember löytyy design-puolelta ihan kyseisen komponentin Properties-listasta.

ari kood [20.09.2017 08:30:07]

#

Designer yrittää tunkea sarakkeita kahdesti datagridviewiin (rivit 10 ja 15). Kun kommentoin tuon toisen rivin pois, toimii juttu kuin pitääkin.

Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container()
        Dim Uc_test1 As WindowsApplication21.uc_test
        '
        '
        Uc_test1 = New WindowsApplication21.uc_test()
        '
        '
        Uc_test1.Columns.AddRange(New System.Windows.Forms.DataGridViewColumn() {Me.Column1, Me.Column2})
        '
        '
        Uc_test1.DGV.AutoGenerateColumns = False
        Uc_test1.DGV.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
        Uc_test1.DGV.Columns.AddRange(New System.Windows.Forms.DataGridViewColumn() {Me.Column1, Me.Column2})
        '
        '
        '
        'Column1
        '
        Me.Column1.HeaderText = "Column1"
        Me.Column1.Name = "Column1"
        '
        'Column2
        '
        Me.Column2.HeaderText = "Column2"
        Me.Column2.Name = "Column2"
'
'
        Me.Controls.Add(Uc_test1)

    End Sub

Tämän johtuu nyt nähtävästi tuosta kun minulla on kaksi propertya periaatteessa samasta asiasta. Ja molempien on pakko olla DesignerSerializationVisibility.Content, muuten ei toimi kuin pitäisi. Ja molempia tarvitaan;
- DGV, jotta MyColumnsEditor löytää dgv:n, ja että voin asettaa esim. datasourcen tai pääsen hämmentämään muitakin propertyja.
- Columns, jotta pääsen muokkaamaan sarakkeita.

Public Class uc_test

    <Browsable(True)>
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
    Public ReadOnly Property DGV As DataGridView
        Get

            Return Me.DataGridView1

        End Get
    End Property


    <Editor(GetType(MyColumnEditor), GetType(UITypeEditor))>
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
    Public ReadOnly Property Columns As DataGridViewColumnCollection
        Get
            Return Me.DataGridView1.Columns

        End Get

    End Property

End Class

uc_test.Datagridview1 componentille on siis annettu datasource DGV-propertyn alta. Kaikki datasourcen sarakkeet ilmestyvät oikein dgv:lle. Mutta nyt kun haluan piilottaa osan sarakkeista, ei se onnistu DGV-propertyn kautta (Object reference not set to an instance of an object.). Sarakkeiden piilottaminen onnistuu itse tehdyn usercontrollin Columns-propertyn kautta, mutta aina kun teen muutoksia columns-propertyyn, ilmestyy tuo toinen rivi designer koodiin eikä ajo enää onnistu. Ja aina kun teen muutoksia DGV-propertyyn, palautuu alkuperäiset sarakkeet näkyville.

Mikä eteen? Nyt meni taas sormi suuhun.

edit: ehkä sittenkin pitäisi saada tuo .getfield toimimaan. Mutta tarvitsen kuitenkin tuon DGV-propertyn.

ari kood [01.10.2017 08:05:59]

#

Luovutin (jo 21.9), en löytänyt ratkaisua. Teen tarvittavat muutokset koodilla form load eventissä.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta