[C#, Linq] Bepalen SelectedItem van combobox

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik ben weer aan het stoeien met LINQ en ik probeer een combobox te vullen via LINQ en als de selectie is gewijzigd dat de gegevens van de selectie in labels wordt getoond.
Allemaal niet zo heel spannend ;)
Hier de code om te combobox te vullen:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        public void fillVisibleLayers(frmLayers frm)
        {
            var visibleLayers = from l in Layers.Cast<Layer>()
                                where l.Visible == true
                                orderby l.GlobalPosition descending
                                select new { Name = l.Name
                                                        , LayerHandle = l.Handle
                                                        , LayerType = l.LayerType };

            frm.cboLayers.DataSource = visibleLayers.ToArray();
            frm.cboLayers.DisplayMember = "Name";
            frm.cboLayers.ValueMember = "LayerHandle";
            frm.cboLayers.SelectedValue = _mapWin.Layers.CurrentLayer;
        }

Bovenstaande code werkt zoals bedoeld.

Het gaat mis bij het opvragen van SelectedItem:
C#:
1
2
3
4
5
6
7
8
9
10
11
        private void cboLayers_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Get data from combobox
            var selectedLayerItem = cboLayers.SelectedItem;
            if (selectedLayerItem != null)
            {
                lblHandle.Text = "Handle: " + selectedLayerItem.LayerHandle.ToString();
                lblName.Text = "Name: " + selectedLayerItem.Name.ToString();
                lblType.Text = "Type: " + selectedLayerItem.LayerType.ToString();
            }
        }

selectedLayerItem.LayerHandle bestaat niet. Als ik selectedLayerItem in QuickWatch bekijk, zie ik:
{LayerHandle=9, Name="test", LayerType="Point"}
Dus de properties zijn wel bekend. Maar ik denk dat ze niet benaderbaar zijn op de manier dat ik doe, omdat ze Anonymous zijn.
Hoe moet ik dat dan wel doen?

Via Google kwam ik op veel voorbeelden waar een aparte classe wordt gebruikt:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
    public class MyLayersList
    {
        public string Name { get; set; }
        public int LayerHandle { get; set; }
        public eLayerType LayerType { get; set; }

        // This is neccessary because the ListBox and ComboBox rely
        // on this method when determining the text to display.
        public override string ToString()
        {
            return Name;
        }
    }

SelectedIndexChanged wordt dan:
C#:
1
2
3
4
5
6
7
8
9
10
11
        private void cboLayers_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Get data from combobox
            var selectedLayerItem = (MyLayersList)cboLayers.SelectedItem;
            if (selectedLayerItem != null)
            {
                lblHandle.Text = "Handle: " + selectedLayerItem.LayerHandle.ToString();
                lblName.Text = "Name: " + selectedLayerItem.Name.ToString();
                lblType.Text = "Type: " + selectedLayerItem.LayerType.ToString();
            }
        }

Dat werkt wel.

Nu is mijn vraag wat is de beste manier om dit op te lossen? Omdat cboLayers.SelectedItem wel alle info lijkt te hebben, lijkt het me wat overbodig om een extra classe te gebruiken.

Verder gebruik ik .ToArray() in de DataSource. In voorbeelden zie ik ook vaak .ToList(). Welke kan ik het beste gebruiken?

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:22
SelectedItem returned een object.
Je zal dus moeten casten (zoals je in je laatste code-voorbeeld doet), zodanig dat je het juiste / gewenste type terugkrijgt.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Gebruik wel het 'as' statement bij het casten. Deze geeft geen foutmelding als het object van een ander type is..

C#:
1
MyClass selectedLayerItem = cboLayers.SelectedItem as MyClass;


Overigens is het denk ik ook verstandig dat je eens naar databinding kijkt. Zowel WinForms als WPF hebben fantastische mogelijkheden. Vooral als je TwoWay binding gebruikt.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • L-VIS
  • Registratie: April 2005
  • Laatst online: 11:15
Wat whoami zegt dus. Je zou ook wat met reflectie kunnen doen als je niet een class wilt aanmaken voor dit geval.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:22
Niemand_Anders schreef op woensdag 19 augustus 2009 @ 09:11:
Gebruik wel het 'as' statement bij het casten. Deze geeft geen foutmelding als het object van een ander type is..
idd, was ik vergeten te zeggen.
Indien je cast met as, en het object is niet van het gewenste type, krijg je gewoon null terug.
Wat whoami zegt dus. Je zou ook wat met reflectie kunnen doen als je niet een class wilt aanmaken voor dit geval
Hij moet volgens mij helemaal niet nog eens een eigen class maken.
Hij heeft toch al zijn 'Layer' class (zie eerste codevoorbeeld)

[ Voor 26% gewijzigd door whoami op 19-08-2009 09:24 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Bedankt voor alle reacties.
Ik zal inderdaad eens kijken of ik het met mijn 'Layer' class kan oplossen.
Ik heb nu de code niet bij me, maar zal vanavond gelijk proberen.

Acties:
  • 0 Henk 'm!

  • creator1988
  • Registratie: Januari 2007
  • Laatst online: 11-09 14:44
In .Net 4 is dit opgelost door gebruik van het dynamic keyword.

Waarom doe je eigenlijk

code:
1
2
3
                                select new { Name = l.Name
                                                        , LayerHandle = l.Handle
                                                        , LayerType = l.LayerType };

ipv
code:
1
select l;


Dan kan je casten naar Layar. Wat je ook al had.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:22
creator1988 schreef op woensdag 19 augustus 2009 @ 10:22:
In .Net 4 is dit opgelost door gebruik van het dynamic keyword.
Hoe dan ?
Waarom doe je eigenlijk

code:
1
2
3
                                select new { Name = l.Name
                                                        , LayerHandle = l.Handle
                                                        , LayerType = l.LayerType };

ipv
code:
1
select l;


Dan kan je casten naar Layar. Wat je ook al had.
Idd; ik snap ook niet waarom hij daar een anonymous type creeërt.... 8)7

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • L-VIS
  • Registratie: April 2005
  • Laatst online: 11:15
whoami schreef op woensdag 19 augustus 2009 @ 09:23:
Hij moet volgens mij helemaal niet nog eens een eigen class maken.
Hij heeft toch al zijn 'Layer' class (zie eerste codevoorbeeld)
Klopt maar ik probeerde een moeilijke oplossing te bedenken :). Namelijk als hij het vullen van zijn combolijst niet wil aanpassen (idd met een anonnymous type). De makkelijkste oplossing is idd zoals creator1988 aangeeft, maar ik had het idee dat TS dit om wat voor reden dan ook niet wilde aanpassen.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb mijn select zo gemaakt omdat de Layer class veel meer properties bevat dan dat ik nodig heb.
Misschien is het wel beter om select l te doen en het hele Layer object in een combobox te zetten.
Dat zal ik ook vanavond even uitproberen.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:22
En waarom zou je dan eigenlijk nog eens een nieuw object maken ?
Ik bedoel, ik zie het voordeel ervan niet.
Gewoon je Layer object idd in de combobox zetten; de properties die je niet nodig hebt, gebruik je dan simpelweg niet. Ze zitten ook niet in de weg.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • DutchCommando
  • Registratie: November 2000
  • Laatst online: 09:21
Niemand_Anders schreef op woensdag 19 augustus 2009 @ 09:11:
Gebruik wel het 'as' statement bij het casten. Deze geeft geen foutmelding als het object van een ander type is..

C#:
1
MyClass selectedLayerItem = cboLayers.SelectedItem as MyClass;


Overigens is het denk ik ook verstandig dat je eens naar databinding kijkt. Zowel WinForms als WPF hebben fantastische mogelijkheden. Vooral als je TwoWay binding gebruikt.
Als je er zeker van bent dat een object van een bepaald type is dan zou ik een expliciete cast gebruiken in plaats van het 'as' keyword. Dit geeft namelijk beter aan wat jij als programmeur verwacht dat je code doet. Simpelweg altijd 'as' gebruiken omdat er dan niet een eventuele InvalidCast of NullPointer voorbijkomt is wat mij betreft niet correct.

Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 11:03

Haan

dotnetter

DutchCommando schreef op woensdag 19 augustus 2009 @ 16:36:
[...]


Als je er zeker van bent dat een object van een bepaald type is dan zou ik een expliciete cast gebruiken in plaats van het 'as' keyword. Dit geeft namelijk beter aan wat jij als programmeur verwacht dat je code doet. Simpelweg altijd 'as' gebruiken omdat er dan niet een eventuele InvalidCast of NullPointer voorbijkomt is wat mij betreft niet correct.
Niet mee eens!
Als de code altijd doet wat je 'verwacht' dat het doet, zou het hele exception handling ook niet nodig zijn. (snap je waar ik heen wil? ;) )
Het gebruik van het 'as' keyword vind ik persoonlijk ook netter staan en je kan er makkelijker mee checken of de cast is gelukt (checken op null ipv exception opvangen..). Als je niet zeker bent van het type gebruik je eerst nog het 'is' keyword.

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:22
Waarom zou je nog is gebruiken als je as gebruikt ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 11:03

Haan

dotnetter

whoami schreef op woensdag 19 augustus 2009 @ 17:09:
Waarom zou je nog is gebruiken als je as gebruikt ?
Ik gebruik het in situaties waarbij een object een aantal mogelijke types kan zijn.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
public void Example(object obj)
{
    if (obj is Foo)
    {
        Foo foo = obj as Foo;
    }
    else if (obj is Bar)
    {
        Bar bar = obj as Bar;
    }
    else throw new ArgumentException("Parameter must be of type Foo or Bar", obj);
}

Kater? Eerst water, de rest komt later


  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Haan schreef op woensdag 19 augustus 2009 @ 17:26:
[...]

Ik gebruik het in situaties waarbij een object een aantal mogelijke types kan zijn.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
public void Example(object obj)
{
    if (obj is Foo)
    {
        Foo foo = obj as Foo;
    }
    else if (obj is Bar)
    {
        Bar bar = obj as Bar;
    }
    else throw new ArgumentException("Parameter must be of type Foo or Bar", obj);
}
En waarom zou je niet gewoon een overloaded method gebruiken? Dan heb je namelijk ook direct compiler controle en dus minder kan op runtime errors welke een exception raisen. Zeker als je een goed gelayered model hebt waarin design patterns worden gebruikt hebben exceptions vrijwel altijd een gigantische stacktrace.

C#:
1
2
3
4
5
6
7
8
9
10
11
public void TypedExample(Foo foo)
{
}

public void TypedExample(Bar bar)
{
}

FooBar fb = new FooBar();
TypedExample(fb); // <-- geeft compiler error
Example(fb); // <-- raised Argumentexception, maar compiled wel..

Behalve compiler support, vind ik overloaded methods code ook beter leesbaar. Vooral als een methode meerdere types ondersteund.

If it isn't broken, fix it until it is..


  • creator1988
  • Registratie: Januari 2007
  • Laatst online: 11-09 14:44
Niemand_Anders schreef op donderdag 20 augustus 2009 @ 09:37:
[...]

En waarom zou je niet gewoon een overloaded method gebruiken? Dan heb je namelijk ook direct compiler controle en dus minder kan op runtime errors welke een exception raisen. Zeker als je een goed gelayered model hebt waarin design patterns worden gebruikt hebben exceptions vrijwel altijd een gigantische stacktrace.

C#:
1
2
3
4
5
6
7
8
9
10
11
public void TypedExample(Foo foo)
{
}

public void TypedExample(Bar bar)
{
}

FooBar fb = new FooBar();
TypedExample(fb); // <-- geeft compiler error
Example(fb); // <-- raised Argumentexception, maar compiled wel..

Behalve compiler support, vind ik overloaded methods code ook beter leesbaar. Vooral als een methode meerdere types ondersteund.
Dit hoor je gewoon met een interface op te lossen. Typesafe, een method entry, klaar.

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

creator1988 schreef op donderdag 20 augustus 2009 @ 09:40:
[...]
Dit hoor je gewoon met een interface op te lossen. Typesafe, een method entry, klaar.
Mag jij een interface verzinnen voor deze overloaded methods:
C#:
1
2
3
4
5
6
7
public void TypedExample(string code)
{
}

public void TypeExample(int id)
{
}

Helaas kun je niet alles met interfaces oplossen. Daarnaast was de issue waarom je 'is' zou gebruiken ipv van 'as'. Het argument zou zijn dat het handig is als je method argument van het type object zou zijn. In dergelijke gevallen vind ik overloaded methods een nettere implementatie.

En wie zegt dat Foo en Bar uberhaupt overeenkomsten hebben? Misschien betreft het wel een constructor voor een NntpClient en kun je zowel de hostname (string) als het IPAddess doorgeven. De hostname overload zal dan eerst via DNS het IPAdress opvragen.

In elk geval moet object als argument type zoveel mogelijk vermeden worden. Dat zou kunnen met een interface, maar helaas niet altijd.

If it isn't broken, fix it until it is..


  • DutchCommando
  • Registratie: November 2000
  • Laatst online: 09:21
Haan schreef op woensdag 19 augustus 2009 @ 16:59:
[...]

Niet mee eens!
Als de code altijd doet wat je 'verwacht' dat het doet, zou het hele exception handling ook niet nodig zijn. (snap je waar ik heen wil? ;) )
Het gebruik van het 'as' keyword vind ik persoonlijk ook netter staan en je kan er makkelijker mee checken of de cast is gelukt (checken op null ipv exception opvangen..). Als je niet zeker bent van het type gebruik je eerst nog het 'is' keyword.
In feite zeg laat je met het 'as' keyword de volgende gedachte achter: "Hmmm, deze ComboBox kan nog andere type items bevatten dan T, daarom maakt de programmeur hier gebruik van het 'as' keyword".

Wat je wil doen als alle items in de ComboBox van hetzelfde type zijn is het volgende:
1. Controleren of het geselecteerde item niet null is.
2. Expliciet casten naar het verwachte type.

Uit die inslag kan ik halen dat er niet perse een item geselecteerd hoeft te zijn in de ComboBox. Daarnaast weet ik dat de verwachting is dat enkel items van type T in de ComboBox aanwezig zijn.
Niemand_Anders schreef op donderdag 20 augustus 2009 @ 10:44:
[...]

En wie zegt dat Foo en Bar uberhaupt overeenkomsten hebben? Misschien betreft het wel een constructor voor een NntpClient en kun je zowel de hostname (string) als het IPAddess doorgeven. De hostname overload zal dan eerst via DNS het IPAdress opvragen.

In elk geval moet object als argument type zoveel mogelijk vermeden worden. Dat zou kunnen met een interface, maar helaas niet altijd.
Als zij geen overeenkomsten hebben dan zou ik me afvragen waarom ze wel in hetzelfde stuk code gebruikt worden OF de overeenkomst expliciet gaan maken in een abstractie.
Pagina: 1