In a windows forms payroll application employing MVP pattern (for a small scale client) I'm planing user permission handling as follows (permission based) as basically its implementation should be less complicated and straight forward.
NOTE : System could be simultaneously used by few users (maximum 3) and the database is at the server side.
This is my UserModel. Each user has a list of permissions given for them.
class User
{
string UserID { get; set; }
string Name { get; set; }
string NIC {get;set;}
string Designation { get; set; }
string PassWord { get; set; }
List <string> PermissionList = new List<string>();
bool status { get; set; }
DateTime EnteredDate { get; set; }
}
When user log in to the system it will keep the current user in memory.
For example in BankAccountDetailEntering view, I can control the permission to access command button as follows.
public partial class BankAccountDetailEntering : Form
{
bool AccountEditable {get; set;}
public BankAccountDetailEntering ()
{
InitializeComponent();
}
private void BankAccountDetailEntering_Load(object sender, EventArgs e)
{
cmdEditAccount.enabled = false;
OnLoadForm (sender, e); // Event fires...
If (AccountEditable )
{
cmdEditAccount.enabled=true;
}
}
}
In this purpose my all relevant presenters (like BankAccountDetailPresenter) should aware of UserModel as well in addition to the corresponding business Model it is presenting to the View.
class BankAccountDetailPresenter
{
BankAccountDetailEntering _View;
BankAccount _Model;
User _UserModel;
DataService _DataService;
BankAccountDetailPresenter( BankAccountDetailEntering view, BankAccount model, User userModel, DataService dataService )
{
_View=view;
_Model = model;
_UserModel = userModel;
_DataService = dataService;
WireUpEvents();
}
private void WireUpEvents()
{
_View.OnLoadForm += new EventHandler(_View_OnLoadForm);
}
private void _View_OnLoadForm(Object sender, EventArgs e)
{
foreach(string s in _UserModel.PermissionList)
{
If( s =="CanEditAccount")
{
_View.AccountEditable =true;
return;
}
}
}
public Show()
{
_View.ShowDialog();
}
}
So I'm handling the user permissions in the presenter iterating through the list. Should this be performed in the Presenter or View? Any other more promising ways to do this?
Thanks.
"The presenter acts upon the model and the view. It retrieves data from repositories (the model), and formats it for display in the view." - MVP
So the presenter formats the data, but for me it looks like presenter contains kind of business logic - it really checks if user can modify account. What if you forget this check in one of the forms? So it should be in the underlying layer (probably, service).
Related
Im making Login Window in my app based on Caliburn.Micro mvvm framework. So, how to return an property (for example, true if user passed good data or false, if he pass bad credentials) from TryClose() method from my Login Window that is initialize by Caliburn.Micro? How to get information from window opened in IWindowManager.ShowDialog()?
First, my MainWindowViewModel.cs:
using Caliburn.Micro;
namespace TaskManager.ViewModels
{
class MainWindowViewModel : Conductor<IScreen>.Collection.OneActive
{
protected override void OnViewLoaded(object view)
{
IWindowManager manager = new WindowManager();
//Login page, context is data with user's lists
LoginViewModel loginView = new LoginViewModel(context);
manager.ShowDialog(loginView, null, null);
//here i want to get info, if i get logged properly or not
}
public void LoadUserInfoPage() //here starts "main" program
{
ActivateItem(new UserInfoViewModel());
}
//and so on...
}
}
My LoginViewModel.cs:
namespace TaskManager.ViewModels
{
class LoginViewModel : Screen
{
public string Login { get; set; }
public string Password { get; set; }
public LoginViewModel(FakeData context)
{
this.context = context;
}
public void LoginButton()
{
bool check = Services.Login.IsValid(Login, Password, context);
if(check) //if login is OK, check == true
TryClose();
}
private FakeData context { get; set; } //data is here
}
}
Then, my IsValid() Method:
namespace TaskManager.Services
{
static class Login
{
static public bool IsValid(string login, string password, FakeData context)
=> context.users.Any(i => i.Login == login);
//i know it is bad, but its only example
}
}
Buttons, opening and closing windows works great (reading from textboxes too). I want only get info (maybe by reference?) if user is pass good data.
THanks for your advices!
You can make use of EventAggregator for the purpose.
"An Event Aggregator is a service that provides the ability to publish
an object from one entity to another in a loosely based fashion. "
The first step would be create instance of EventAggregator in your ViewModels and subscribe to it. You can do it via DI in constructor of both ViewModels.
For LoginViewModel,
private IEventAggregator _eventAggregator;
public LoginViewModel(FakeData context,IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
And MainWindowViewModel,
private IEventAggregator _eventAggregator;
public MainWindowViewModel (IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);
}
The next step is to create a Message Object, which can transmit the required information between the ViewModels.
public class OnLoginAttemptMessage
{
string UserName { get; set; }
bool IsLoginSuccessful { get; set; }
}
Finally, it is time to put everything together. In youg LoginButton method in LoginViewModel, we modify the code to raise the event on successfull login.
public void LoginButton()
{
bool check = Services.Login.IsValid(Login, Password, context);
if(check) //if login is OK, check == true
{
_eventAggregator.PublishOnUIThread(new OnLoginAttemptMessage
{
UserName = Login,
IsLoginSuccessful = check;
});
TryClose();
}
}
The last step is in MainWindowViewModel, where you need to implement the IHandle interface.
class MainWindowViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<OnLoginSuccessMessage>
{
public void Handle(OnLoginSuccessMessage message)
{
if(message.IsLoginSuccessful)
{
// Login is successfull, do next steps.
}
}
}
You can read more on EventAggregator here (https://caliburnmicro.com/documentation/event-aggregator)
So I am a little confused as to how the MVVM architecture can help me and how to use it in this situation:
I am using Xamarin and have created my view and view controller in iOS as an example. I have implemented MVVMLight toolkit as well, and have created my ViewModel for the view and view controller.
I am creating a login screen, so the user inputs their username and password and they are updated in the model through RaisePropertyChanged() events. My question is where I need to call the function to validate this information and actually log them into the system?
I have implemented a RelayCommand that will call a method on the ViewModel whenever the button is clicked as I have seen in other tutorials and such, but I am not sure if I am supposed to call the validation code here.
Some examples of what I have:
LoginViewModel.cs:
public class LoginViewModel : ViewModelBase
{
private string _username;
private string _password;
public RelayCommand LoginButtonCommand { get; private set; }
public bool CanExecuteLoginCommand { get; set; }
public LoginViewModel()
{
LoginButtonCommand = new RelayCommand(HandleLoginButtonCommand, () => CanExecuteLoginCommand);
CanExecuteLoginCommand = true;
}
public string Username
{
get
{
return _username;
}
set
{
_username = value;
RaisePropertyChanged(() => Username);
}
}
public string Password
{
get
{
return _password;
}
set
{
_password = value;
RaisePropertyChanged(() => Password);
}
}
private void HandleLoginButtonCommand()
{
CanExecuteLoginCommand = false;
//Validate login?
CanExecuteLoginCommand = true;
}
}
LoginViewController.cs:
public partial class LoginViewController : UIViewController
{
private Binding _usernameTextFieldBinding;
private Binding _passwordTextFieldBinding;
private LoginViewModel _viewModel;
public LoginViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
_viewModel = Application.Locator.Login;
HideKeyboardHandling(UsernameTextField);
HideKeyboardHandling(PasswordTextField);
_usernameTextFieldBinding = this.SetBinding(
() => _viewModel.Username)
.ObserveSourceEvent("EditingDidEnd")
.WhenSourceChanges(() => _viewModel.Username = UsernameTextField.Text);
_passwordTextFieldBinding = this.SetBinding(
() => _viewModel.Username)
.ObserveSourceEvent("EditingDidEnd")
.WhenSourceChanges(() => _viewModel.Password = PasswordTextField.Text);
Loginbutton.SetCommand("TouchUpInside", _viewModel.LoginButtonCommand);
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
void HideKeyboardHandling(UITextField textField)
{
textField.ShouldReturn = TextField =>
{
TextField.ResignFirstResponder();
return true;
};
var gesture = new UITapGestureRecognizer(() => View.EndEditing(true));
gesture.CancelsTouchesInView = false;
View.AddGestureRecognizer(gesture);
}
}
It all depends on how strict you want to be with Single Responsibility Principle(SPR). Which in turn depends on how complex your application is. The more complex the application is, the more separated the responsibilities should be.
A typical MVVM implementation handles the commands in the ViewModel. And the ViewModel forwards the call into the Model. But his still puts two responsibilities(e.g. presentation and command handling) into a single component, a.k.a the ViewModel.
A more strict approach will be to have the ViewModel only handle presentation logic. Create a separate controller to host all the command handlers. And have the command handlers forward the calls to the Model.
A more relaxed approach will be to simply implement the business logic in the ViewModel. This implies you don't have a business logic layer. Which is fine if your application is simple enough that a business logic layer does not worth the effort.
I'm new to MVVM and am converting a WinForms project to WPF using the MVVM Light framework. Most introductions to MVVM emphasize that a business model should have no knowledge of a view model. So I'm modifying my business models to support my new view models through the addition of public properties and property-changed events.
But this feels awkward when I just want to get user input that I'm not going to save in the model. In WinForms, I would do it this way in my business model:
dlg.ShowDialog();
string someValue = dlg.SomeValue;
// Use someValue in a calculation...
Is this really anathema to MVVM:
window.ShowDialog();
string someValue = _ViewModelLocator.MyVm.SomeValue;
It saves me from having to create a public property in the business model for what only really needs to be a local variable.
Thanks for advice & insights.
Here's a post I wrote on unit testing a user-interaction (i.e. dialogs).
I recommend using an interface to wrap around your user interaction logic.
Leveraging a user interface with delegates will provide an object oriented solution.
The thought process is to unit test your user interaction without user intervention.
In addition, I added this implementation for discovery on Nuget.
I believe the class name on that dll that you want to use is called UserInteraction.
public delegate MessageBoxResult RequestConfirmationHandler(object sender, ConfirmationInteractionEventArgs e);
public interface IConfirmationInteraction
{
event RequestConfirmationHandler RequestConfirmation;
MessageBoxResult Confirm();
}
public class ConfirmationInteraction : IConfirmationInteraction
{
#region Events
public event RequestConfirmationHandler RequestConfirmation;
#endregion
#region Members
object _sender = null;
ConfirmationInteractionEventArgs _e = null;
#endregion
public ConfirmationInteraction(object sender, ConfirmationInteractionEventArgs e)
{
_sender = sender;
_e = e;
}
public MessageBoxResult Confirm()
{
return RequestConfirmation(_sender, _e);
}
public MessageBoxResult Confirm(string message, string caption)
{
_e.Message = message;
_e.Caption = caption;
return RequestConfirmation(_sender, _e);
}
}
}
public class ConfirmationInteractionEventArgs : EventArgs
{
public ConfirmationInteractionEventArgs() { }
public ConfirmationInteractionEventArgs(string message, string caption, object parameter = null)
{
Message = message;
Caption = caption;
Parameter = parameter;
}
public string Message { get; set; }
public string Caption { get; set; }
public object Parameter { get; set; }
}
This is my first C# application, entirely self-taught without any prior software programming background. I did some research on Undo/Redo but could not find anything helpful (or easy to understand). Therefore, I'm hoping someone can help me in designing undo/redo function for my program (winforms application). The application consist of a main form where subsequent child forms will be called to record user specified values during certain events (button clicks etc). After every event is handled, a bitmap will be drawn in buffer and then loaded to a picturebox within the main form during the OnPaint event of the main form. Each input in separated into custom class objects and added into separate List and BindingList. Objects contained within List are used for graphics (to indicate coordinates etc) while objects in BindingList are used to display some important values on DataGridView. Just to give a brief description, the codes look something like this:
public partial class MainForm : form
{
public class DataClass_1
{
public double a { get; set; }
public double b { get; set; }
public SubDataClass_1 { get; set; }
}
public class SubDataClass_1
{
public double x { get; set; }
public double y { get; set; }
public string SomeString { get; set; }
public CustomEnum Enum_SubDataClass_1 { get; set; }
}
public class DisplayDataClass
{
public string SomeString { get; set; }
public double e { get; set; }
public double f { get; set; }
}
public enum CustomEnum { Enum1, Enum2, Enum3 };
// Lists that contain objects which hold the necessary values to be drawn and displayed
public List<DataClass_1> List_1 = new List<DataClass_1>();
public List<DataClass_2> List_2 = new List<DataClass_2>(); // Object has similar data types as DataClass_1
public BindingList<DisplayDataClass> DisplayList = new BindingList<DisplayDataClass>();
Bitmap buffer;
public MainForm()
{
InitializeComponent();
dgv.DataSource = DisplayList;
}
private void DrawObject_1()
{
// some drawing codes here
}
private void DrawObject_2()
{
// some drawing codes here
}
protected override void OnPaint(PaintEventArgs e)
{
DrawObject_1();
DrawObject_2();
pictureBox1.Image = buffer;
}
// Event to get input
private void action_button_click(object sender, EventArgs e)
{
ChildForm form = new ChildForm(this);
form.ShowDialog();
Invalidate();
}
}
The child forms' codes look something like this:
public partial class ChildForm : form
{
public ChildForm(MainForm MainForm)
{
InitializeComponent();
// Do something
}
private void ok_button_click(object sender, EventArgs e)
{
DataClass_1 Data_1 = new DataClass_1();
DisplayDataClass DisplayData = new DisplayDataClass();
// Parsing, calculations, set values to Data_1 and DisplayData
MainForm.List_1.Add(Data_1);
MainForm.DisplayList.Add(DisplayData);
this.DialogResult = System.Windows.Forms.DialogResult.OK;
this.Close();
}
}
Since all necessary data are stored in the lists and will only be changed after certain events are triggered (mostly button clicks), therefore I tried to use these lists to determine the state of the application during run time. My approach in implementing the undo/redo function is by adding the following codes:
public partial class MainForm : form
{
public class State()
{
public List<DataClass_1> List_1 { get; set; }
public List<DataClass_2> List_2 { get; set; }
public BindingList<DisplayDataClass> DisplayList { get; set; }
// and so on
public State()
{
List_1 = new List<DataClass_1>();
List_2 = new List<DataClass_2>();
DisplayList = new BindingList<DisplayDataClass>();
}
}
State currentState = new State();
Stack<State> undoStack = new Stack<State>();
Stack<State> redoStack = new Stack<State>();
private void MainForm_Shown(object sender, EventArgs e)
{
// Saves original state as first item in undoStack
undoStack.Push(currentState);
}
protected override void OnPaint(PaintEventArgs e)
{
// Update lists from currentState before drawing
List_1 = new List<DataClass_1>(currentState.List_1);
List_2 = new List<DataClass_2>(currentState.List_2);
DisplayList = new BindingList<DisplayDataClass>(currentState.DisplayList);
}
// When undo button is clicked
private void undo_button_Click(object sender, EventArgs e)
{
if (undoStack.Count > 0)
{
redoStack.Push(currentState);
undoStack.Pop();
currentState = undoStack.Last();
Invalidate();
}
}
// When redo button is clicked
private void redo_button_Click(object sender, EventArgs e)
{
// Have not thought about this yet, trying to get undo done first
}
// Events that trigger changes to values held by data objects
private void action_button_Click(object sender, EventArgs e)
{
// Replace the following code with previously stated version
if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
ChildForm form = new ChildForm(this)
UpdateState();
undoStack.Push(currentState);
Invalidate();
}
}
// To update currentState to current values
private void UpdateState()
{
currentState.List_1 = new List<DataClass_1>(List_1);
currentState.List_2 = new List<DataClass_2>(List_2);
currentState.DisplayList = new BindingList<DisplayDataClass>(DisplayList);
// and so on
}
}
Result:
The application does not perform the undo function correctly. The program shows the correct output under normal conditions but when the undo event is triggered, regardless of how many objects have been drawn, the application reverts back to initial state (the state where there is no recorded data). I've used System.Diagnostics.Debug.WriteLine() during events where the stack is changed to check the number of counts within undoStack and it seems to give the correct counts. I'm guessing that the lists need to be copied/cloned in a different manner? Or am I doing something wrong here? Can anyone please guide me? Performance, readability, resource management, future maintenance and etc need not be considered.
There are a lot of approaches that will work, each with different strengths and weaknesses, but I generally like to define an abstract Action class and then a separate UndoRedoStack class.
The Action class would have two methods (Do and Undo) which each subclassed Action can implement. You isolate any logic that can "change state" to these Action subclasses thereby keeping that logic neatly encapsulated.
The UndoRedoStack is like a regular stack except with three core methods.
ApplyAction (like Push)
UndoAction (like Pop, but be sure to only
move the pointer/index without truncating or throwing away any
existing actions).
RedoAction (like Push, but you use the next value
already in the underlying stack/list instead of pushping/inserting a
new one).
Usually I find the biggest challenge then becomes designing each Action subclass in such a way that it maintains enough information to both undo and redo itself. But being able to encapsulate all state manipulation logic to individual Action subclasses usually makes it easiest for me to maintain in the long run.
You are storing reference objects in your stacks. If you want your method to work, you need to implement a clone() method in your state object, and store a new clone each time, otherwise, changes made are made to each member of the stack, as they all point to the same reference object.
I've been looking all over the web for example implementations of an MVC setup in .NET. I have found many examples but they all seem to differ in certain aspects. I have a book on Design Patterns that described that MVC was originated in Smalltalk so I read over several people discussing its implementation in that language. What follows is an example project I wrote utilizing what I gathered was a proper implementation but I've been confused by a few details.
One problem I run into is the proper order of the construction of the objects. Here is the impl in my Program.cs
Model mdl = new Model();
Controller ctrl = new Controller(mdl);
Application.Run(new Form1(ctrl, mdl));
The View:
Immediately I have a couple of issues I'm unsure of. First, if the view is supposed to only read data from the Model for updating, but contains a reference to it, what is stopping me from making the calls the controller does to the model from the view? Should a programmer just ignore the fact that they are exposed to the models member functions? Another thought I had, was perhaps the event that informs the view the model is updated, would send some sort of state object for the view to update itself with.
public interface IView
{
double TopSpeed { get; }
double ZeroTo60 { get; }
int VehicleID { get; }
string VehicleName { get; }
}
/// <summary>
/// Assume the form has the following controls
/// A button with a click event OnSaveClicked
/// A combobox with a selected index changed event OnSelectedIndexChanged
/// A textbox that displays the vehicles top speed named mTextTopSpeed
/// A textbox that displays the vehicles zero to 60 time named mTextZeroTo60
/// </summary>
public partial class Form1 : Form, IView
{
private IController mController;
private IModel mModel;
public Form1(IController controller, IModel model)
{
InitializeComponent();
mController = controller;
mController.SetListener(this);
mModel = model;
mModel.ModelChanged += new ModelUpdated(mModel_ModelChanged);
}
void mModel_ModelChanged(object sender, EventArgs e)
{
mTextTopSpeed.Text = mModel.TopSpeed.ToString();
mTextZeroTo60.Text = mModel.ZeroTo60.ToString();
}
public double TopSpeed { get { return Double.Parse(mTextTopSpeed.Text); } }
public double ZeroTo60 { get { return Double.Parse(mTextZeroTo60.Text); } }
public int VehicleID { get { return (int)mComboVehicles.SelectedValue; } }
public string VehicleName { get { return mComboVehicles.SelectedText; } }
#region Form Events
private void OnFormLoad(object sender, EventArgs e)
{
mComboVehicles.ValueMember = "Key";
mComboVehicles.DisplayMember = "Value";
mComboVehicles.DataSource = new BindingSource(mModel.VehicleList, null);
}
private void OnSelectedIndexChanged(object sender, EventArgs e)
{
mController.OnSelectedVehicleChanged();
}
private void OnSaveClicked(object sender, EventArgs e)
{
mController.OnUpdateVehicle();
}
#endregion
}
The Controller:
My only real issue with the way I have implemented the controller is that it seems a bit odd to me that is possible to construct the controller without definitely having a view assigned to it. I could ignore the view entirely but that would mean I would pass parameters to the controller's functions for updating the model which seems to miss the point entirely.
public interface IController
{
void OnUpdateVehicle();
void OnSelectedVehicleChanged();
void SetListener(IView view);
}
class Controller : IController
{
private IModel mModel;
private IView mView = null;
public Controller(IModel model)
{
mModel = model;
}
public void OnUpdateVehicle()
{
if(mView == null)
return;
mModel.UpdateVehicle(mView.VehicleID, mView.TopSpeed, mView.ZeroTo60);
}
public void SetListener(IView view)
{
mView = view;
}
public void OnSelectedVehicleChanged()
{
if (mView == null)
return;
mModel.SelectVehicle(mView.VehicleID);
}
}
The Model:
In my form, I have a combobox that is a list of the vehicles given in my pseudo database. I feel as though my form should actually implement multiple Views / Models because of this. A view specific to listing the possible vehicles with a corresponding controller / model, and a view for displaying information about the selected vehicle with its own controller / model.
public delegate void ModelUpdated(object sender, EventArgs e);
public interface IModel
{
event ModelUpdated ModelChanged;
void UpdateVehicle(int id, double topSpeed, double zeroTo60);
void SelectVehicle(int id);
double TopSpeed { get; }
double ZeroTo60 { get; }
IDictionary<int, string> VehicleList { get; }
}
// class for the sake of a pseudo database object
class Vehicle
{
public int ID { get; set; }
public string Name { get; set; }
public double TopSpeed { get; set; }
public double ZeroTo60 { get; set; }
public Vehicle(int id, string name, double topSpeed, double zeroTo60)
{
ID = id;
Name = name;
TopSpeed = topSpeed;
ZeroTo60 = zeroTo60;
}
}
class Model : IModel
{
private List<Vehicle> mVehicles = new List<Vehicle>()
{
new Vehicle(1, "Civic", 120.0, 5.0),
new Vehicle(2, "Batmobile", 9000.0, 1.0),
new Vehicle(3, "Tricycle", 5.0, 0.0)
};
private Vehicle mCurrentVehicle;
public Model()
{
mCurrentVehicle = mVehicles[0];
}
public event ModelUpdated ModelChanged;
public void OnModelChanged()
{
if (ModelChanged != null)
{
ModelChanged(this, new EventArgs());
}
}
public double TopSpeed { get { return mCurrentVehicle.TopSpeed; } }
public double ZeroTo60 { get { return mCurrentVehicle.ZeroTo60; } }
public IDictionary<int, string> VehicleList
{
get
{
Dictionary<int, string> vDict = new Dictionary<int, string>();
foreach (Vehicle v in mVehicles)
{
vDict.Add(v.ID, v.Name);
}
return vDict as IDictionary<int, string>;
}
}
#region Pseudo Database Calls
public void SelectVehicle(int id)
{
foreach (Vehicle v in mVehicles)
{
if (v.ID == id)
{
mCurrentVehicle = v;
OnModelChanged(); // send notification to registered views
break;
}
}
}
public void UpdateVehicle(int id, double topSpeed, double zeroTo60)
{
foreach (Vehicle v in mVehicles)
{
if (v.ID == id)
{
mCurrentVehicle.TopSpeed = topSpeed;
mCurrentVehicle.ZeroTo60 = zeroTo60;
OnModelChanged(); // send notification to registered views
break;
}
}
}
#endregion
}
In Conclusion of this tl;dr, I guess what I'm looking for, is some guidance on whether or not what I'm doing here represents a true MVC implementation and maybe for someone to shed some light on the aforementioned concerns. Any advice would be greatly appreciated.
We'll it depends on what you want to do. You currently have an implementation of the Supervising Controller. If you wish to remove the model from the view (and any databinding), you can implement a Passive View pattern instead. See this article for more differences.
(source: microsoft.com)
And Martin Fowler is king (GUI Architectures).