tutorials.de Buch-Aktion 05/2012
ERLEDIGT
NEIN
ANTWORTEN
4
ZUGRIFFE
378
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Darkas Darkas ist offline Mitglied Gold
    Registriert seit
    Feb 2007
    Beiträge
    218
    HI!

    Ich hab ein kleines Problem mit meiner Architektur: ich möchte einen Wizard für neue Projekte einbauen. Dieser besteht folglich aus mehreren Fenstern (zwingend, es geht nicht über verschiedene Panel oder ähnliches). Um das ganze aber sauber aufzubauen würde ich gerne eine Klasse bereitstellen, die den Wizard startet, und anschließend wenn er durchgelaufen ist, das ergebniss wiedergibt.
    Dazu möchte ich die Fenster nur über diese Klasse erreichbar machen. Und genau da ist das problem. Ich kann die Fenster schlecht in die Klasse selbst implementieren, da ich sonst schwierigkeiten mit dem Designer hätte, und es ist auch nicht möglich, die Klassen öffentlich zugänglich zu machen, weil ich sehr pingelich bei sauberen Architekturen bin. Was mir noch einfallen würde wäre internal, aber dazu müsste ich die Klassen in ein Assembly auslagern (oder geht das vielleicht auch anders?), und das möchte ich ehrlich gesagt auch nicht, da das weitere Schwierigkeiten zur folge hätte (das würde zu lange dauern um das zu erklären). Hat jemand einen Vorschlag? Wäre wür jede Hilfe dankbar!
     

  2. #2
    Konstantin Denerz Tutorials.de Gastzugang
    Hallo Darkas,

    also wenn ich dich richtig verstanden habe, willst du das gleiche in .Net implementieren wie der Wizard in Eclipse implmementiert ist, von daher schau doch mal im Code von Eclipse nach wie die es gemacht haben. Ansonsten folgender Vorschlag:
    Entwickele doch einen generischen Wizard. Das heißt dass du z.B. eine WizardPage implementierst, die notwendige Informationen erfasst und in ein Dictionary speichert. Dazu einen WizardController der die WizardPages aufnimmt und die Navigation sowie die Ausführung der WizardPage-Validierung übernimmt. Dann sollte es einen WizardPresenter geben der die den WizardController übergeben bekommt und dessen Methoden ausführt. Der WizardPresenter kann über den Controller auf das aktuelle Page zugreifen und das z.B. Panel (ControlContainer) anzeigen. Hier ist etwas Pseudo-Code:

    Code csharp:
    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
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    
     
     
     
    using System;
    using System.Collections;
    namespace GenericWizard.Model
    {
        
        /// <author>kde-se</author>
        public interface IWizardPage<TControl>
        {
            string Title
            {
                get;set;
            }
            
            string Description
            {
                get;set;
            }
            
            TControl ControlContainer
            {
                get;
            }
            
            IDictionary Validate(IDictionary theContainer);
        }
    }
     
     
    using System;
    using System.Drawing;
    using System.Windows.Forms;
     
    namespace GenericWizard.Model.Internal
    {
        /// <author>kde-se</author>
        public abstract partial class AbstractWizardPage : Form, IWizardPage<Panel>
        {
            public AbstractWizardPage()
            {
                InitializeComponent();
                panel = new Panel();
                this.Controls.Add(panel);
            }
            
            public string Title {
                get { return title; }
                set { title = value; }
            } private string title;
            
            public string Description {
                get { return description; }
                set { description = value; }
            } private string description;
            
            /// <summary>
            /// Holds the container of controls used to present in the wizard presenter.
            /// </summary>
            public System.Windows.Forms.Panel ControlContainer {
                get { return panel; }
            } private Panel panel;
            
            /// <summary>
            /// Validate the wizard page.
            /// </summary>
            /// <remarks>The data container contains a list of errors with 'errors' as key and
            /// a list with strings as value, if the validation failed.</remarks>
            /// <param name="theContainer">Holds the input data from wizard page if validation is successful,
            /// else a list of errors.</param>
            /// <returns>The extended data container</returns>
            public System.Collections.IDictionary Validate(System.Collections.IDictionary theContainer)
            {
                //validate the wizard page
                throw new NotImplementedException();
            }
            
        }
    }
     
     
     
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using GenericWizard.Model.Internal;
    namespace GenericWizard.Controller
    {
        /// <author>kde-se</author>
        public interface IWizardController
        {
            void AddPage(AbstractWizardPage aPage);
            void RemovePage(AbstractWizardPage aPage);
            void NextPage();
            void PreviousPage();
            IList<string> Errors
            {
                get;
            }
            
            AbstractWizardPage CurrentPage
            {
                get;
            }
            
            
            WizardConclusion Conclude;
        }
        
        delegate IDictionary WizardConclusion(IDictionary aContainer);
    }
     
     
     
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using GenericWizard.Controller;
    namespace GenericWizard.UI.Internal
    {
        /// <author>kde-se</author>
        public partial class WizardPresenter : Form, IWizardPresenter
        {
            public WizardPresenter(IWizardController theController)
            {
                
                InitializeComponent();
                
                this.controller = theController;
            }
            
            public IWizardController Controller {
                get { return controller; }
                set { controller = value; }
            } private IWizardController controller;
            
            void Button2Click(object sender, EventArgs e)
            {
                controller.NextPage();
                //this.Panel.Parent = controller.CurrentPage.ControllContainer
            }
        }
    }

    Wenn du das so ähnlich machst kannst du den Wizard in einer Assembly kapseln und deine WizardPages in deinem Projekt von AbstractWizardPage ableiten. Damit brauchst du eigentlich nur die Controls über den GUI-Designer zusammenzustecken und die Validierungsmethode zu implementieren. Diese erstellten WizardPages anschließend dem Controller hinzuzufügen und den an eine Instanz von WizardPresenter weiter zu geben. Müsste eigentlich so funktionieren. Sobald auf dem WizardPresenter ein Finish Button gedrückt wird soll dann das Delegate WizardConclusion ausgeführt werden.

    Gruß Konstantin
    Geändert von Konstantin Denerz (13.09.08 um 23:21 Uhr)
     

  3. #3
    Darkas Darkas ist offline Mitglied Gold
    Registriert seit
    Feb 2007
    Beiträge
    218
    Das klingt schon ganz brauchbar, allerdings hätte ich es lieber so, dass alle Fensterklassen nur über meinen WizardProvider erreichbar sind. So als ob sie darin geschachtelt und private sind. Ich könnte sie zwar in ein Assembly auslagern, und als internal definieren, abe da hätte ich halt den nachteil mit dem Assembly, was auch wieder zu komplikationen führt. Gibt es da vielleicht eine Lösung?
     

  4. #4
    Darkas Darkas ist offline Mitglied Gold
    Registriert seit
    Feb 2007
    Beiträge
    218
    also ich hab mal folgendes Probiert: ich habe den WizardProvider zu einer partial class gemacht, und um meine einzelnen Dialogfenster ebenfalls ein partial WizardProvider gemacht. Es startet auch, allerdings habe ich jetzt ein problem mit der Lokalisierung: er findet den inhalt meiner in die Form geschachtelten *.resx Datei nicht mehr. Das ganze funktioniert mit dem üblichen getResources, wie man es von der lokalisierung kennt. Hat da jemand eine Lösung?
     

  5. #5
    Avatar von Norbert Eder
    Norbert Eder Norbert Eder ist offline Mitglied Diamant
    Registriert seit
    Feb 2004
    Ort
    Österreich / Graz
    Beiträge
    5.137
    Blog-Einträge
    51
    1) Zahlreiche Fenster in diesem Zusammenhang sehe ich persönlich als recht schmutzig an. Alles löst sich mit entsprechenden Controls lösen, daher widerspreche ich deinem Satz aus der ersten Post.
    2) Für das von dir gewünschte Verhalten würde ich eine eigene Assembly erstellen, zumal man diese ohnehin wieder in eine einzige Assembly zusammenfassen kann.
    3) Ich selbst bin kein großer Fan der .NET Ressourcen Behandlung, verwende diesbezüglich daher meine eigenen Routinen, die hier auch recht wenig Stress machen, im Gegensatz zu dem von dir erwähnten Verfahren.