Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/averrunci/windowsformsmvc
Windows Forms MVC is a class library for Windows Forms with Model View Controller architecture.
https://github.com/averrunci/windowsformsmvc
c-sharp mvc winforms
Last synced: about 2 months ago
JSON representation
Windows Forms MVC is a class library for Windows Forms with Model View Controller architecture.
- Host: GitHub
- URL: https://github.com/averrunci/windowsformsmvc
- Owner: averrunci
- License: mit
- Created: 2018-07-17T08:22:37.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2023-12-08T05:13:02.000Z (about 1 year ago)
- Last Synced: 2024-04-26T21:47:32.986Z (9 months ago)
- Topics: c-sharp, mvc, winforms
- Language: C#
- Homepage:
- Size: 3.71 MB
- Stars: 1
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
- License: LICENSE
Awesome Lists containing this project
README
## Overview
Windows Forms MVC is a class library for Windows Forms with Model View Controller architecture.
![Windows Forms MVC overview](Images/mvcsummary.png)
In Windows Forms MVC, the roles of a model, view, and controller are redefined as follows.
### Model
The model represents an object model in the presentation domain.
It has its properties, its internal states, events that occur when its internal states are changed, that are usually normal .NET events, and so on,
but does not have any business logic.
It is similar to Presentation Model, but unlike to Presentation Model, it does not have main presentaion logic.
It has only behaviors for internal states that is encapsulated.
It has also references to other models and sends messages to each other.### View
The view represents an appearance of the model.
As it knows a model associated with it, values of its properties are set by binding values of the model.### Controller
The controller handles events that occur on the view by using the model associated with the view.
It has a reference to the business domain and sends a message to it to execute business logic.
Its reference to the business domain is usually injected by DI container.The basic flow is as follows;
1. An event occurs on the view or on other domain.
1. The controller receives it and sends an appropriate message to the model.
1. The model updates its internal states.
1. The view receives the change of the model and updates its appearance.## Features
### View
The ContentViewAttribute is provided to specify the model associated with the view to the view.
The DataContextSource is provided to set the instance of the model associated with the view.
When the DataContextChanged event of the DataContextSource occurs, the value of the model should be bound to the property of the view.Instead of using the DataContextSource, the DataContext property and the DataContextChanged event of the Control can be used.
The WindowsFormsController is provided to associate controllers that handle events on the view with the view.
The view should be set to the View property of the WindowsFormsController.The typical implementation of the view is as follows;
``` csharp
[ContentView(typeof(LoginContent))]
public class LoginView : UserControl
{
private IContainer components;
private WindowsFormsController windowsFormsController;private TextBox userIdTextBox;
...protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}private void InitializeComponent()
{
components = new Container();windowsFormsController = new WindowsFormsController(components);
windowsFormsController.View = this;userIdTextBox = new TextBox();
...SuspendLayout();
Controls.Add(userIdTextBox);DataContextChanged += LoginView_DataContextChanged;
...
ResumeLayout(false);
}private readonly ObservablePropertyBindings observablePropertyBindings = new ObservablePropertyBindings();
public LoginView()
{
InitializeComponent();
}private void BindContent(LoginContent loginContent)
{
// The value of the model is bound to the property of the Control.
observablePropertyBindings.BindTwoWay(loginContent.UserId, userIdTextBox, nameof(userIdTextBox.Text));
...
}private void UnbindContent()
{
// The value of the model is unbound from the property of the Control.
observablePropertyBindings.Unbind();
}private void LoginView_DataContextChanged(object? sender, EventArgs e)
{
UnbindContent();
(DataContext as LoginContent).IfPresent(BindContent);
}
}
```The ContentControl is provided to show the view with which the model is associated.
The ContentControl searches the view attributed by the ContetViewAttribute by the model that is set to the Content property and the instance of the model is set to the DataContext and the DataContextSource of the view.### Controller
The ViewAttribute is provided to specify a controller to handle events that occur on the view.
``` csharp
[View]
class Controller {...}
```The view to which the controller is attached is specified using the following properties.
- ViewType
The type of the view to which the controller is attached is specified.
- Key
The key of the view to which the controller is attached is specified. The name of the data context type can also be specified as the key.
The condition to search the controller is as follows;
1. whether the value of the ViewType is equal to the type of the view if the ViewType is specified. If the ViewType is not specified, the controller is the target.
1. whether the value of the Key is equal to the key of the view if the Key is specified. If the Key is not specified, the controller is the target. If the key of the view is not specified, search whether the Key is equal to:1. the name of the data context type.
1. the full name of the data context type.
1. the full name of the data context type without parameters if its type is generics.
1. the name of the base type of the data context.
1. the name of the interface that is implemented by the data context.Note: This library does not provide a feature to specify the Key to the view. If the Key should be specified, add an implementation to find a key from the view by implementing the IElementKeyFinder interface.
A controller can be created with a factory that implements IWindowsFormsControllerFactory. If a factory is not specified, a default factory that creates a controller with Activator.CreateInstance method is used.
``` csharp
class ControllerFactory : IWindowsFormsControllerFactory {...}
`````` csharp
WindowsFormsController.DefaultControllerFactory = new ControllerFactory();
```The attributes are provided to inject event handlers, a data context, and controls to the controller.
The available attributes are as follows.#### EventHandlerAttribute
This attribute is specified to the method to handle an event.
It is also specified to the property or the field that is defined with a delegate.
The method is declared as follows;- No argument.
``` csharp
[EventHandler(ElementName = "ActionButton", Event = "Click")]
private void OnActionButtonClick()
{
// implements the action.
}
```- One argument that is a second argument of EventHandler.
``` csharp
[EventHandler(ElementName = "ActionButton", Event = "Click")]
private void OnActionButtonClick(EventArgs e)
{
// implements the action.
}
```- Two arguments that are a first argument and a second argument of EventHandler.
``` csharp
[EventHandler(ElementName = "ActionButton", Event = "Click")]
private void OnActionButtonClick(object? sender, EventArgs e)
{
// implements the action.
}
```If the method name is "[ElementName]_[EventName]", this attribute does not have to be specified.
``` csharp
private void ActionButton_Click()
{
// implements the action.
}private void ActionButton_Click(EventArgs e)
{
// implements the action.
}private void ActionButton_Click(object? sender, EventArgs e)
{
// implements the action.
}
```If the method is an async method, its suffix can be "Async".
``` csharp
private async Task ActionButton_ClickAsync()
{
// implements the action.
}private async Task ActionButton_ClickAsync(EventArgs e)
{
// implements the action.
}private async Task ActionButton_ClickAsync(object? sender, EventArgs e)
{
// implements the action.
}
```### FromDIAttribute
This attribute is specified to the parameter. Its parameter value is injected using the dependency injection.
``` csharp
private void ActionButton_Click([FromDI] IDataLoader dataLoader)
{
// implements the action.
}private void ActionButton_Click(EventArgs e, [FromDI] IDataLoader dataLoader)
{
// implements the action.
}private void ActionButton_Click(object? sender, EventArgs e, [FromDI] IDataLoader dataLoader)
{
// implements the action.
}
```### FromElementAttribute
This attribute is specified to the parameter.
Its parameter value is injected from the element of the specified parameter name in the view to which the controller is attached.
If the name of the element is different from the parameter name,
the name of the element is specified to the Name property of the FromElementAttribute.``` csharp
private void ActionButton_Click([FromElement] Control control)
{
// implements the action.
}private void ActionButton_Click(EventArgs e, [FromElement(Name = "Control")] Control control)
{
// implements the action.
}private void ActionButton_Click(object? sender, EventArgs e, [FromElement] Control control)
{
// implements the action.
}
```### FromDataContextAttribute
This attribute is specified to the parameter. Its parameter value is injected from the data context of the view
to which the controller is attached.``` csharp
private void ActionButton_Click([FromDataContext] DataContextType dataContext)
{
// implements the action.
}private void ActionButton_Click(EventArgs e, [FromDataContext] DataContextType dataContext)
{
// implements the action.
}private void ActionButton_Click(object? sender, EventArgs e, [FromDataContext] DataContextType dataContext)
{
// implements the action.
}
```#### DataContextAttribute
This attribute is specified to the field, property, or method to which a DataContext is injected.
The method has an argument the type of which is the one of a DataContext.
The implementation is as follows;- Field
``` csharp
[DataContext]
private DataContexType? dataContext;
```- Property
``` csharp
[DataContext]
public DataContexType? DataContext { get; set; }
```- Method
``` csharp
[DataContext]
public void SetDataContext(DataContexType? dataContext)
{
this.dataContext = dataContext;
}
private DataContexType? dataContext;
```If the method name is "SetDataContext", this attribute does not have to be specified.
``` csharp
private void SetDataContext(DataContextType? dataContext)
{
this.dataContext = dataContext;
}
private DataContextType? dataContext;
```#### ElementAttribute
This attribute is specified to the field, property, or method to which a control is injected.
The method has an argument whose type is the one of a control.
The control whose name is equal to the one of field, property, or method is injected.
When the name of the method starts with "Set", the target name of the method is the value removed "Set" from the method name.
If the name of the control is different from the one of the field, property, or method,
the name of the control is specified to the Name property of the ElementAttribute.
The implementation to inject a control whose name is "Element" is as follows;- Field
``` csharp
[Element(Name = "Control")]
private Control? control;
```- Property
``` csharp
[Element]
public Control? Control { get; set; }
```- Method
``` csharp
[Element]
public void SetControl(Control? control)
{
this.control = control;
}
private Control? control;
```## NuGet
[WindowsFormsMvc](https://www.nuget.org/packages/WindowsFormsMvc/)
## LICENSE
This software is released under the MIT License, see LICENSE.