2

Nous avons une application Silverlight. Il a quelques pages qui se trouvent à l'intérieur des onglets de notre interface utilisateur. Dans le passé, nous les avons appelés SavePage et PanelPage. La page d'enregistrement ne dispose que des fonctionnalités de base pour éditer les détails d'un enregistrement, créer de nouveaux enregistrements et supprimer l'enregistrement existant à l'écran. PanelPage hérite de SavePage. PanelPage est un peu plus sophistiqué dans la mesure où les panneaux deviennent visibles/invisibles en fonction des sélections que vous faites à l'écran.Quel motif de conception ai-je trouvé?

Le code était un désordre énorme dans l'application Silverlight. Mais, récemment, j'ai pris l'étape du portage de ce code pour travailler dans Xamarin Forms. J'ai fait deux tentatives ratées pour ce faire, et lors de ma troisième tentative, j'ai obtenu le code pour travailler sur toutes les plates-formes ciblées: Silverlight, iOS, Android et Windows UWP. Je suis assez content de la conception de la classe pour le moment. Cela pourrait être plus simple, mais cela fera l'affaire pendant un moment.

Le but de cette conception est que la logique d'interface utilisateur soit séparée des contrôles d'interface utilisateur physiques eux-mêmes. J'ai supprimé les utilisations System.Windows du code partagé qui se trouve sur les deux plates-formes (SavePage et PanelPage). Ces pages sont plus comme des «contrôleurs» dans les modèles MVC ou MVVC. Mais, je ne pense pas que ce que j'ai créé est exactement l'un ou l'autre de ces deux modèles. Cependant, j'ai dû diviser ces classes en deux parties: une pour les appels abstraits de l'interface utilisateur comme SaveAsync(), et une pour les appels d'interface utilisateur spécifiques à la plate-forme comme ReportError. Je me bats pour obtenir le nom des classes juste puisque je ne sais même pas quel modèle de conception j'utilise.

Voici un diagramme de classes: Class Diagram Voici le code pour certaines des interfaces concernées:

public interface IPage : IRecordSelector 
{ 
    /// <summary> 
    /// This event should be raised when the busy state of a tab changes 
    /// </summary> 
    event EventHandler<BusyStateChangedEventArgs> BusyStateChanged; 
    object PageElement { get; } 
} 

public interface IButtonDrivenPage : IPage 
{ 
    Task SaveClickAsync(); 
    Task DuplicateClickAsync(); 
    Task DeleteClickAsync(); 
    Task NewClickAsync(); 
    event EventHandler<ButtonVisibilityChangedEventArgs> ButtonVisibilityChanged; 
    IRecord GetRecord(); 
} 

public interface ISavePage : IButtonDrivenPage, IRequestClose 
{ 
    string DataContextXmlSnapshot { get; } 
    bool PromptForChangeCancel { get; } 
    IRecord SelectedItem { get; } 
    Task SetSelectedItemAsync(IRecord selectedItem); 
    event EventHandler SelectedItemChanged; 
    void Close(); 
    void SetAutomationObject(object automationObject); 
    ISavePageUIController SavePageUIController { get; } 
} 

public interface ISavePageUIController: IDisposable 
{ 
    /// <summary> 
    /// The UI controller is notifying the page that the UI content has been loaded 
    /// </summary> 
    event EventHandler ContentLoaded; 

    /// <summary> 
    /// Prompt the user for a yet or a no 
    /// </summary> 
    Task<bool> GetYesNoFromPrompt(string message, string title); 

    /// <summary> 
    /// Report an error to the user 
    /// </summary> 
    void ReportError(string title, string message, Exception exception); 

    /// <summary> 
    /// Notifies the UI that the DataContext/Binding context has changed 
    /// </summary> 
    void SetSelectedItem(IRecord selectedItem); 

    /// <summary> 
    /// The actual UI object that is displayed on screen as the content of the page 
    /// </summary> 
    object PageElement { get; } 

    /// <summary> 
    /// Clears residual errors from the screen if they exist 
    /// </summary> 
    void ClearErrors(); 

    /// <summary> 
    /// The record was saved. The selectedItem parameter will be the saved record from the server. 
    /// </summary> 
    void CurrentRecordSaved(IRecord selectedItem); 

    /// <summary> 
    /// This event occurs when the UI wants to notify the controller that a Save button has been clicked in the UI somewhere 
    /// </summary> 
    event EventHandler SaveClicked; 
} 


public interface IPanelUIController : ISavePageUIController 
{ 
    void CreateAndAddPanelFromContent(PagePanel pagePanel, double? panelHeight); 
    IEnumerable<IPagePanel> GetIPagePanelControls(); 
    void SetHeader(IPanelHeader pageHeader); 
    void SetVisiblePanels(IList<bool> visiblePanels); 
    void HideAllPanels(); 
    event EventHandler<RecordsSelectedRoutedEventArgs> PanelPageRecordsSelected; 
} 

Ces interfaces ont été mises en œuvre avec succès dans les formulaires Silverlight et Xamarin. Donc, est-ce similaire à un autre modèle de conception d'interface utilisateur? Quelqu'un peut-il recommander des améliorations? Ou, dites-moi ce que je devrais faire pour le convertir en un modèle de conception d'interface utilisateur plus standard? Que diriez-vous de nommer? Que dois-je nommer mes classes et interfaces ici?

Répondre

2

Pour être honnête, je ne serais pas trop obsédé par être l'un ou l'autre (MVC, MVVM ou MVP), ils sont à peu près les mêmes et le but est de garder cette "grosse séparation". Cela dit, en ce moment, vous semblez IMHO être plus proche de MVP (Model View Présentateur)

Le problème est que vous avez beaucoup de logique entremêlés il: IPage devrait vraiment être juste un View mais vous l'avez faire choses que le contrôleur le ferait généralement. Même avec ses enfants: ISavePage a une méthode appelée SetAutomation objet que je m'attendrais normalement à voir dans un Controller (au moins si je devine correctement sur sa fonction). Adam Freeman a fait un excellent travail en parlant de la façon de casser ces choses dans ASP.NET MVC 5: http://enos.itcollege.ee/~ijogi/Nooks/Pro%20ASP.NET%20MVC%205/Pro%20ASP.NET%20MVC%205.9781430265290.pdf Vérifiez la page 51 où il décompose ce que chaque élément devrait être conceptuellement, ce qui peut aider?

Je voudrais essayer de le faire de cette façon, étant donné que nous avons établi que votre IPage est vraiment un contrôleur.

public class PageElement 
{ 
    IPageController _controller; 

    // these are your models - your controller will simply allow them to be shown with your other methods 
    private PageData _data; 
    private PageData _otherData; 

    public PageElement(IPageController ctrl) 
    { 
     _controller = ctrl; 
    } 
} 

public class PageController : IPageController 
{ 
    IPageService _service; 

    public PageController(IPageService service) 
    { 
      _service = service; 
    } 

    // this is what your button calls when clicked 
    public void SaveAsync(object sender, SomeEventArgs args) 
    { 
      // the service does the actual work 
      _service.SaveAsync() 
    } 
} 

public class PageService : IPageService 
{ 
    public void SaveAsync(){ // what it does} 

} 
+0

Je peux voir vos points ici. Le problème est que IPage n'est pas vraiment une vue. La propriété PageElement est l'objet UI que la plate-forme va afficher à l'écran, mais à part ça, l'interface IPage est vraiment le contrôleur. Historiquement, il s'appelait IPage, mais j'ai envisagé de le renommer IPageController. –

+0

Il serait juste de dire que PageElement ne devrait pas exister sur le contrôleur, mais la façon dont notre système fonctionne est qu'une classe IPage est instanciée, puis l'élément PageElement est ajouté à l'arborescence Visual. –

+0

Je vous entends - voici ce que je ferais comme exemple: en supposant que IPage est le contrôleur, je l'appellerais simplement IPageController. Il devrait être limité à la gestion des éléments de page et à la mise à jour des données d'un service. Ce service devrait être un objet distinct qui fonctionne réellement. Donc vous auriez un PageElement qui contient un IPageController en tant que membre. Le IPageController devrait alors avoir son propre service (IPageService) pour que les méthodes SaveClickAsync appellent simplement une méthode dans votre service pour gérer la sauvegarde et les choses de cette nature. – prestonsmith

0

Regardez comme un MVC ou motif de contrôleur vue précédente (avant MVC)