Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C#] Objectdatasource property-descriptions als columns

Pagina: 1
Acties:
  • 291 views sinds 30-01-2008
  • Reageer

  • ThaLaw
  • Registratie: Maart 2001
  • Laatst online: 25-11 09:41
oke, beetje kromme titel misschien, maar het moest ergens over gaan en in het vakje passen.
Wat ik bedoel is het volgende:

Ik heb talloze gridviews in mijn project, gekoppeld aan objectdatasoures.
Deze consumen de public properties van talloze classes
(bijv Users, Departments, Orders etc. etc.)

De kolommen in de gridview krijgen als naam de naam van de property als ze 'gebind' worden. Nu is dit niet in alle gevallen de naam die ik aan de gebruikers wil tonen. Zo is bijvoorbeeld een property van de class Users genaamd RecordLastChanged.
De column-header wordt nu ook RecordLastChanged, terwijl ik hier liever heb staan 'Laatst gewijzigd'.

Ik kan me voorstellen dat het framework hier best een oplossing voor heeft, maar ik weet even niet hoe. Misschien het overriden van een method GetPropertynames in de class o.i.d. ? Maar hoe? Welke interface moet ik implementeren?

Programmatically de kolomhoofden zetten is not done, aangezien er teveel datasources zijn. Het moet echt in de classes gedefinieerd kunnen worden.

  • Flard
  • Registratie: Februari 2001
  • Laatst online: 25-11 23:28
Of er een kant-en-klare oplossing is weet ik niet, maar wat je zou een eigen Attribute kunnen maken (bijvoorbeeld 'CaptionAttribute'), en dan een van de binding events van de datasource opvangen, en dan zelf de captions erbij gaan zoeken via reflection.
(jouwobject.GetType().GetCustomAttributes(typeof(CaptionAttribute))[0])

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Je zou eventueel iets met de PropertyDescriptor klasse kunnen doen. Als je dan op je properties het DescriptionAttribute gebruikt kun je die via de PropertyDescriptor achterhalen en op die manier de friendly-name uitvogelen.

Nu met Land Rover Series 3 en Defender 90


  • ThaLaw
  • Registratie: Maart 2001
  • Laatst online: 25-11 09:41
Beide adviezen klinken goed, ben aan de slag gegaan, maar ben er niet uitgekomen.

In eerste instantie geprobeerd een eigen Custom Data Source Control te maken, die inherit van ObjectDataSource control.
Ik kom er alleen niet achter wellke method of event ik moet overriden, zodat ik ipv de standaard properties, de friendlyname attribute van de property retourneer.

Ik heb een gridview die aan deze custom data source gebind is, maar deze blijft hardnekkig de propertynames als kolomhoofden tonen.

Moet ik de DataBind method overriden? Hier spelen returnvalues geen rol, dus hoe beïnvloed ik dit dan?

De tip over PropertyDescriptor geprobeerd te vertalen, maar zonder success. Hoe zorg ik ervoor dat de methodes die databound controls aanroepen om kolom informatie te verkrijgen, mijn vervangende methods gebruiken. Ik weet niet eens welke methods dit zijn :o

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Wat je kunt doen is het ColumnAdded event afvangen en daarin de HeaderText van de kolom aanpassen.
Zoiets:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// dataGrid is de DataGridView
dataGrid.ColumnAdded += new DataGridViewColumnEventHandler(HandleColumnAdded);

private void HandleColumnAdded(object sender, DataGridViewColumnEventArgs e) {
    // Pak de column
    DataGridViewColumn column = e.Column;

    // Datasource van de DataGridView
    object dataSource = column.DataGridView.DataSource;

    // Haal de properties op
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(dataSource);

    // Zoek het property
    PropertyDescriptor foundProperty = properties.Find(column.DataPropertyName, true);

    // Als het property bestaat dan de Description doorzetten op column.HeaderText
    if(foundProperty != null) {
        column.HeaderText = foundProperty.Description;
    }
}

Behoorlijk quick-n-dirty :)

Nu met Land Rover Series 3 en Defender 90


  • ThaLaw
  • Registratie: Maart 2001
  • Laatst online: 25-11 09:41
Ik kom er toch niet uit |:(

Ik ben tegen de volgende link aangelopen: http://www.dotnet247.com/247reference/msgs/5/26486.aspx

Dit kreeg ik niet aan de praat met mijn gridview. bovendien werkte dit nog iets anders, omdat je eigenlijke object gewrapt wordt in een ander object. Ik wil dat mijn dataobjecten inheriten van een class die deze zaken regelt.

De oplossing met de datagridview werkte ook niet, omdat ik vergeten was te zeggen dat het hier om ASP.NET gaat. Dus geen DataGridView, maar slechts een GridView, die deze events niet heeft.

Ik vraag me af of het allemaal de moeite nog waard is :o, maar ik blijf nog even sleutelen vandaag, mochten jullie op basis van dit verhaaltje nog andere tips hebben dan graag :)

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

ASP.Net dus. Op zich ook geen probleem het is alleen iets meer een hack dan een nette oplossing.
Probeer het volgende eens:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public partial class _Default : System.Web.UI.Page  {
    private List<Entity> data;
    private bool columnsBound;

    protected void Page_Load(object sender, EventArgs e) {
        this.data = new List<Entity>();

        for (int i = 0; i < 40; i++) {
            this.data.Add(new Entity(i));
        }

        this.mainGrid.ItemDataBound += new DataGridItemEventHandler(mainGrid_ItemDataBound);
        this.mainGrid.DataSource = this.data;
        this.mainGrid.DataBind();
    }

    private void mainGrid_ItemDataBound(object sender, DataGridItemEventArgs e) {
        if (columnsBound) {
            return;
        }

        columnsBound = true;
        Type boundType = null;

        if (this.mainGrid.DataSource is IList) {
            IList list = (IList)mainGrid.DataSource;
            boundType = list[0].GetType();
        }

        if (boundType == null) {
            return;
        }

        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(boundType);

        for (int i = 0; i < e.Item.Cells.Count; i++) {
            PropertyDescriptor property = properties.Find(e.Item.Cells[i].Text, true);
            if (property != null) {
                e.Item.Cells[i].Text = property.Description;
            }
        }
    }
}

Met de class Entity:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Entity
{
    private int _id;
    private string _test;

    [Description("Identificatie")]
    public int Id
    {
        get { return _id; }
        set { _id = value; }
    }

    [Description("Test omschrijving")]
    public string Test
    {
        get { return _test; }
        set { _test = value; }
    }

    public Entity(int id)
    {
        this._id = id;
        this._test = "Test nummer " + id;
    }
}


Resultaat wordt dan:
IdentificatieTest omschrijving
0Test nummer 0
1Test nummer 1
2Test nummer 2

Het probleem met AutoGenerateColumns en een DataGrid is dat deze columns niet in de Columns property terecht komen. Daarom moet er dus eea gehackt worden om de tekst van de headers te zetten. Aangezien een DataGrid toch een html <table> bouwt kun je het 1e row pakken en daar via het Cells property de tekst van de headers aanpassen. (1e row is DataSource index -1 == header).

Ik zou je overigens wel aanraden om de DataGrid te overriden omdat je dit niet op elke pagina wil doen :P

Edit:
sources zijn hier te downloaden.

[ Voor 6% gewijzigd door MTWZZ op 05-10-2007 11:46 ]

Nu met Land Rover Series 3 en Defender 90


  • ThaLaw
  • Registratie: Maart 2001
  • Laatst online: 25-11 09:41
Thanx a lot!

Het is gelukt.

Ik heb uiteindelijk een GridView overrided.

In de CreateColumns method vervang ik de propertynames door de omschrijving...


C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
protected override ICollection CreateColumns(PagedDataSource dataSource, bool useDataSource)
        {
            // Let the GridView create the default set of columns
            ICollection columnList = base.CreateColumns(dataSource, useDataSource);

            Type boundType=null;

            if (columnList != null && useDataSource)
            {
                if (dataSource.DataSource is IList)
                {
                    boundType = ((IList)dataSource.DataSource)[0].GetType();
                }

                if (boundType != null)
                {
                    foreach (DataControlField f in columnList)
                    {
                        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(boundType);
                        PropertyDescriptor property = properties.Find(f.HeaderText, true);
                        if (property != null)
                        {
                            if (property.Attributes[typeof(GridDescription)] != null)
                            {
                                f.HeaderText = property.Attributes[typeof(GridDescription)].ToString();
                            }
                        }
                    }
                }
            }
            return columnList;
}


..., die ik met een custom GridDescription attribute ...

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field), Serializable()]
    public class GridDescription : Attribute
    {
        String _text;
        public GridDescription(String Text)
            : base()
        {
            _text = Text;
        }
        public override String ToString()
        {
            return _text;
        }
    }


...aan de properties toevoeg van bijvoorbeeld 1 van de dataobjects:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class UserManagerDO
    {
        Collection<User> _users = null;

        public Collection<User> GetUsers()
        {
            if (_users == null)
            {
                MembershipUserCollection _members = Membership.GetAllUsers();
                _users = new Collection<User>();

                foreach (MembershipUser mu in _members)
                {
                    User _u = new User(mu.UserName, mu.LastActivityDate, mu.IsOnline);
                    _users.Add(_u);
                    _users.Add(_u);
                }
            }
            return _users;
        }

        public class User
        {
            private string username = "";
            private DateTime lastlogindatetime;
            private bool currentlyloggedin;

            public User(String UserName, DateTime LastLogin, Boolean CurrentlyLoggedin) 
            {
                username = UserName;
                lastlogindatetime = LastLogin;
                currentlyloggedin = CurrentlyLoggedin;
            }
        
            [GridDescription("Gebruikersnaam")]
            public string UserName
            {
                get { return username; }
                set { username = value; }
            }

            [GridDescription("Laatste keer ingelogd")]
            public DateTime LastLoginDatetime
            {
                get { return lastlogindatetime; }
                set { lastlogindatetime = value; }
            }

            [GridDescription("Online?")]
            public bool CurrentlyLoggedin
            {
                get { return currentlyloggedin; }
                set { currentlyloggedin = value; }
            }
          
        }

    }

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Top!
Vraagje nog, waarom gebruik je een custom attribute? Ben je daar nog speciale dingen mee van plan?

Nu met Land Rover Series 3 en Defender 90


  • ThaLaw
  • Registratie: Maart 2001
  • Laatst online: 25-11 09:41
Nee, niet echt.
Ik kreeg een foutmelding op die Description attribute die jij gebruikte bij de properties van Entity.

Ik kreeg een lege string terug bij property.Description...

Ben ik een namespace vergeten te importeren?

[ Voor 15% gewijzigd door ThaLaw op 05-10-2007 15:57 ]


  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Je moet denk ik even in de gaten houden dat je System.ComponentModel.DescriptionAttribute gebruikt en niet die uit System.EnterpriseServices.

Nu met Land Rover Series 3 en Defender 90

Pagina: 1