[C#] TreeView data & bussines logic

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 10-09 11:15
Momenteel worstel ik met de vraag in hoeverre ik m'n code moet scheiden, wat tot gevolg zou hebben dat ik veel dingen dubbel moet schrijven, en ook gegevens dubbel in het geheugen op moet slaan, en er ook nog is voor moet zorgen dat de gegevens in de TreeView en de eigenlijke gegevens gesynchroniseerd blijven.

Ik heb het nu opgelost door mijn data te laten extenden van de class TreeNode, waardoor ik ze direct aan de TreeView toe kan voegen. Zelf vind ik dit heel netjes werken, omdat ik nu al m'n gevens op 1 plaats heb, en mutaties daarop dus ook maar 1x hoeven te gebeuren. Maar dit staat wel in de weg dat ik de data scheid van de GUI.

Ook zijn er andere dingen die nu veel eenvoudiger op te lossen zijn, omdat voor mijn gevoel nu ook datgene verantwoordelijk is voor wat het moet doen. Ik kan met m'n applicatie bijvoorbeeld dingen afspelen, en daarbij wil ik de huidige actie in de TreeView geselecteerd laten worden. Dat is nu supereenvoudig, omdat mijn data gelijk is aan de te selecteren Node in de TreeView.

Wat is er dan op tegen om het op deze manier op te lossen? Zijn er mensen die een betere/nettere (=hetzelfde :P) oplossing hebben? Ik ben van mening dat codescheiding een goed ding is, mits het niet met allemaal kromme truuks opgelost moet worden.

Een ander voorbeeld: Is het bijvoorbeeld netter om het opslaan van een bestand in een onderliggende class te doen, wanneer dit tot gevolg heeft dat je via events de status door moet geven aan de GUI? Of kan het makkelijker zijn die functie toch ín de GUI op te nemen, waardoor die gelijk toegang heeft tot alle componenten?

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Al wat je nodig hebt is een hashtable waar object -> treenode is opgeslagen en in de treenode sla je in de tag een object op wat alle info bevat om de data die de node representeert weer op te halen (of je object zelf natuurlijk).

Dan wat routines die je data viewen in de treeview en useracties op de nodes vertalen naar acties op de data en klaar. Ik zou NOOIT gui objects gebruiken als datastorage objects.

Het pattern dat hiervoor bedacht is heet MVC (Model View Controller) en dat kun je zo uitgebreid maken als je wilt. Je data is hier het model, de viewer is je treeview en de controller is de logica die de 2 aan elkaar plakt en de acties vertaalt van object naar treenode en vice versa.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 14-09 19:30

alienfruit

the alien you never expected

Je zou ook een virtual treeview kunnen gebruiken, omdat je dan zelf voor de opslag van de treenodes moet zorgen, dit is misschien een goede combinatie.

Acties:
  • 0 Henk 'm!

  • D4Skunk
  • Registratie: Juni 2003
  • Laatst online: 26-07 16:22

D4Skunk

Kind of Blue

Persoonlijk zou ik in dit geval opteren voor een generieke (treenode)controller, die een welbepaalde interface als parameter implementeert :
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
INodeInterface met oa :
string Caption
int IconIndex
...
INodeInterface[] GetChildren
INodeInterface GetParent
void Delete
INodeInterface Insert
INodeInterface Move
Event OnClick
Event OnDoubleClick

...


verder ook het command pattern om je context menus etc te implementeren

Wat ik trouwens niet begrijp is waarom Microsoft deze interfaces niet standaard voorzien heeft bij hun controls... zou me zeer logisch lijken

anyway, my .02 €

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:19
D4Skunk, kan je jouw idee nog ff verder toelichten ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 10-09 11:15
EfBe schreef op zaterdag 01 januari 2005 @ 17:50:
Al wat je nodig hebt is een hashtable waar object -> treenode is opgeslagen en in de treenode sla je in de tag een object op wat alle info bevat om de data die de node representeert weer op te halen (of je object zelf natuurlijk).

Dan wat routines die je data viewen in de treeview en useracties op de nodes vertalen naar acties op de data en klaar. Ik zou NOOIT gui objects gebruiken als datastorage objects.

Het pattern dat hiervoor bedacht is heet MVC (Model View Controller) en dat kun je zo uitgebreid maken als je wilt. Je data is hier het model, de viewer is je treeview en de controller is de logica die de 2 aan elkaar plakt en de acties vertaalt van object naar treenode en vice versa.
Ik heb er het hele weekend over door zitten denken :) Maar is het dan de bedoeling dat ik m'n data in één grote pool gooi, en ze identificeer adhv de hash die opgeslagen is in de TreeNode? Want dit is best een hele mooie oplossing, alleen heb ik dan totaal geen structuur meer in m'n data. Op zich is dit natuurlijk juist het mooie van de oplossing, omdat de data zo gescheiden is van de TreeView, maar wel afhankelijk is van de hiërarchie ervan.

Maar dan nu het probleem: wat als ik die collectie door wil geven aan bijvoorbeeld een andere GUI? Dan kan ik daarin niet meer achterhalen hoe ze geördend moeten worden, want dat weet alleen de TreeView van de eerste GUI...

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Een treeview is een vierwer, geen orderaar of data-store. Jij wilt een hierarchische datastore maken en je gebruikt daarvoor de treeview. Dat is niet nuttig al lijkt het op het eerste gezicht wel zo. Ik weet niet of je data 'parentid' achtige fields heeft zodat je uit een platte bak data altijd je hierarchie weer kan terugvinden, door een O(n) loop (1 keer erdoorheen met een hashtable).

Het punt is nl. dat wanneer je bv alle childs van een gegeven node in een grid wil tonen, je dat niet kunt met je treenodes, maar wel met een normale structuur.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 10-09 11:15
Nou, het punt van mij is dat wanneer ik de data 100% loskoppel van de TreeView ik veel code dubbel moet schrijven en uitvoeren. Eén om de data te updaten, en dan nog een keer (bijna dezelfde code) om de TreeView te updaten.

Voorbeeld: wanneer er in de TreeView een TreeNode naar een andere parent gesleept wordt, moet ik de gesleepte Node kopieren naar de nieuwe parent en vervolgens verwijderen bij de oude. Maar wanneer ik de data gescheiden heb van de TreeView, zal ik deze zelfde acties ook daarop uit moeten voeren om dat ook daarin te bereiken. Mij lijkt dat dus nogal redundant...

Of ik moet deze actie alleen in de bussines logic doorvoeren, en de TreeView gewoon compleet opnieuw laten renderen... Maar dat lijkt mij weer redelijk overdreven zware operatie.

Het andere probleem (afgeleid van hetzelfde): ik ben bezig met een soort macro-achtige tool, en had het uitvoerende gedeelte eerst dus helemaal gescheiden van de GUI. Alleen moest ik toen voor elke statusupdate met events gaan werken, en dus zelf een complete berichtenset opzetten waarin ik in de GUI kon achterhalen wat er moest gebeuren. Nu haal ik (vooralsnog) m'n data direct uit de TreeView, en kan ik dus bij elke actie gewoon ook direct het bijbehorende TreeNode selecteren.

Oh ja, ik werkte toen niet met hashes, maar gewoon met indices. Omdat in dat gedeelte m'n TreeView nooit dieper is dan 2 lagen, kon ik altijd de index van het huidige object en die van de parent doorgeven. Maar ik vond de code er door deze scheiding niet echt duidelijker op worden.

[ Voor 45% gewijzigd door riezebosch op 03-01-2005 10:59 ]

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


Acties:
  • 0 Henk 'm!

  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 10-09 11:15
Hmmmm, haal net een misschien wel heel interessant artikel van veridicus.com
System.Windows.Forms
  • Problem:
    The standard controls such as the TreeView, ListBox and Combo box don't separate the UI from the data. The controls store the data they display themselves rather than requesting the data from a model as required. This way of doing things encourages developers to use the UI controls as a way to store their data (something no self-respecting OO programmer would even begin to consider).
  • Solution 1:
    Use the Model-View-Controller architecture to separate the concerns of data display and data storage. This has the benefit of eliminating the need to store data in two locations (the UI and the storage classes) and releases the developer from having to manually populate and update the UI control.
  • Solution 2:
    Use DataBinding to seperate the UI from the data. This method won't work with TreeViews.
edit:

Weer helemaal ingekort. Men kan ook wel op de link klikken als men hele artikel wil lezen :P


Het probleem met de MVC is dat het níet mogelijk is om de TreeView van .NET aan een andere datasource te koppelen. Wanneer ik dus in een eigen verzamelijk de elementen wil bijhouden, zal ik bij mutaties daarop ook zelf handmatig de gegevensverzameling van de TreeView aan moeten passen. En dit lijkt mij dus redelijk redundant werk :(

[ Voor 147% gewijzigd door riezebosch op 03-01-2005 16:05 ]

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


Acties:
  • 0 Henk 'm!

  • D4Skunk
  • Registratie: Juni 2003
  • Laatst online: 26-07 16:22

D4Skunk

Kind of Blue

whoami schreef op zondag 02 januari 2005 @ 13:40:
D4Skunk, kan je jouw idee nog ff verder toelichten ?
Onder het motto : 'beter veel te laat dan nooit' :

Het standaard mvc-model

Een interface die de volgende functionaliteiten heeft :
code:
1
2
3
4
5
6
7
8
public interface ITreeNode {
    public string Name;
    public string IconIndex;
    public ITreeNode[] Children;
    public ITreeNode Parent;
    public CommandContainer Commands; 
    ....
}


Een klasse die kan werken met de interface ITreeNode en een treeview
code:
1
2
3
4
5
6
public class TreeViewController {
   // initialiseert de treeview met de objecten uit de parameters,
   // en converteert de CommandContainer Commands naar een contextmenu
   TreeViewController(ITreeNode[] parentNodes); 
   ...
}


Je business object moet dan een interface ondersteunen, die de bovengenoemde klasse kan gebruiken om de treeview op te bouwen/events af te handelen, context menus op te vragen etc...

als voorbeeld een bom (bill of materials)

code:
1
2
3
public class BOM : ITreeNode {
   ...
}


Indien je dit enkel gebruikt voor database access , zou je evt. zelfs verder kunnen gaan, en voor je treenode een generieke class gebruiken :

code:
1
2
3
4
5
6
public class TreeNodeDataTable : ITreeNode {
   // initialiseert de klasse adhv een datatable, en alle corresponderende velden 
   //die nodig zijn voor het invullen v/e treeview
    TreeNodeDataTable(DataTable dt,string keyField,string parentField,string nameField,string imageIndexField);
...
}


offtopic:
[gezaag modus]
Wel frustrerend om zelf antwoorden te formuleren, maar het antwoord op je eigen vragen te moeten missen
[/gezaag modus]
Pagina: 1