stati applicativi della GUI e polimorfismo

3

Ho un'applicazione GUI WinForms, che può funzionare in due "stati" con diverse funzionalità, ma questi stati condividono i controlli della GUI. Sto dividendo questi stati usando enum quasi in ogni metodo, come:

    private void picBox_MouseDown(object sender, MouseEventArgs e)
    {
        if (picBox.Image == null)
            return;

        xDown = e.X;
        yDown = e.Y;

        if (appState == AppState.Annotating)
        {
            PointF ptImg = new PointF((xDown - absImgPos.X) * scale,
                (yDown - absImgPos.Y) * scale);
            annotateEngine.AddPoint(e.Location, ptImg);
        }
        else if (appState == AppState.Cropping)
        {
            picBox.Invalidate();
        }
    }

Voglio creare qualcosa come IAppState e implementarlo per i miei stati AnnotatingState::IAppState e CroppingState::IAppState , con alcuni metodi che dovrebbero influenzare la GUI:

interface IAppState
{
    void OnLoadImages();
    void OnSave();
    void OnPathChanged();
    void OnMouseDown();
    void OnMouseUp();
}

Puoi suggerire uno schema adatto?

    
posta Majak 17.08.2016 - 13:51
fonte

2 risposte

5

Uno può utilizzare MVP ( Model View Presenter ) qui. Questo disaccoppia la vista dalla logica della vista e viene in genere utilizzato per rendere le viste scambiabili, ma non vi è alcun motivo per cui non possa essere utilizzato anche per scambiare l'oggetto Presenter (nel caso sia presente un Presenter per ciascuna modalità). Ciò rende essenzialmente il presentatore un oggetto strategia . Questo sarà simile a questo:

public class MyForm : Form, IView
{
    private IPresenter presenter = null;

    public MyForm(AppState appState)
    {
        // For the sake of demonstration, presenters are created here,
        // in the real application they could be injected or switched
        // at run time:
        if (appState == AppState.Annotating)
            presenter = new AnnotatingPresenter(this);
        else
            presenter = new CroppingPresenter(this);
    }
}

L'interfaccia IView deve fornire tutti gli accessi agli elementi / ai controlli del modulo necessari per implementare le loro funzionalità. L'implementazione dell'evento potrebbe essere simile a questa:

 private void picBox_MouseDown(object sender, MouseEventArgs e)
 {
     presenter.OnPicBoxMouseDown(sender,e);
 }

Il metodo correlato nel presentatore di annotazioni è simile al seguente:

void OnPicBoxMouseDown(object sender, MouseEventArgs e)
{
     if (myview.PicBox.Image == null)
        return; 

      var xDown = e.X;
      var yDown = e.Y;
      PointF ptImg = new PointF((xDown - absImgPos.X) * scale,
            (yDown - absImgPos.Y) * scale);
      myView.AnnotateEngine.AddPoint(e.Location, ptImg);
}

Qui, myView è il riferimento al IView passato attraverso il costruttore, e AnnotateEngine e PicBox sono proprietà che devono essere rese disponibili in IView e restituiscono i membri annotateEngine o picBox rispettivamente.

Ovviamente, ecco alcune decisioni di design che puoi ancora fare in modo diverso. Ad esempio, puoi lasciare il codice comune per entrambi gli stati ancora nella picBox_MouseDow della vista, o trovare un posto nel livello del presentatore in cui puoi riutilizzarlo da entrambi i Presentatori (potrebbe essere una classe di strumenti o una classe base comune) . Oppure puoi incapsulare l'accesso di tutti i WinForm di IView in un modo in modo che il livello Presenter non abbia più bisogno di alcun riferimento a WinForms. Dipende dagli obiettivi generali di progettazione, scegli la tua scelta.

    
risposta data 17.08.2016 - 14:37
fonte
0

Vorrei creare classi di moduli separati per gli stati. Sostituisci la parte che crea l'istanza MainForm con un'istruzione switch che crea un AnnotatingForm o un CroppingForm, a seconda dello stato dell'applicazione desiderato.

    
risposta data 17.08.2016 - 22:51
fonte

Leggi altre domande sui tag