I've been using MVP pattern in my application. But I have problems with testing my method which are called after button is clicked. Here is the code:
public interface IControl
{
bool Enabled { get; set; }
string Text { get; set; }
}
public interface IButton : IControl
{
event EventHandler Click;
}
public class Button : System.Windows.Forms.Button, IButton
{ }
public interface IForm : IControl
{
void Show();
void Close();
}
public interface IView : IForm
{
IButton Button1 { get; }
}
public partial class View : Form, IView
{
public View()
{
InitializeComponent();
}
#region IView Members
public IButton Button1
{
get { return button1; }
}
#endregion
}
public class Presenter
{
IView view;
public Presenter(IView view)
{
this.view = view;
this.view.Button1.Click += ButtonClick;
this.view.Show();
}
private void ButtonClick(object sender, EventArgs e)
{
view.Button1.Text= "some text";
}
}
The problem is that I don't know how to write test so that my ButtonClick method get called. I tried like this:
var view = new Mock<IView>();
view.Setup(x => x.Button1).Returns(new Mock<IButton>().SetupAllProperties().Object);
Presenter presenter = new Presenter(view.Object);
view.Raise(x => x.Button1.Click+= null, EventArgs.Empty);
Assert.AreEqual("some text", view.Object.Button1.Text);
I think that problem is in this line:
this.view.Button1.Click += ButtonClick;
It seems that Click event doesn't remember ButtonClick method. How to make Click to be stub to work just normal.
Any suggestion is welcome.
Thanks in advance.
Regards,
Vajda
EDIT: I was able to do that when I created SubscribeOnClick(EventHandler click); method in my IButton interface instead of event EventHandler Click. And I made some ButtonMock where I remembered method. But still, if someone knows for better solution, please share with me.
Maybe it's not a bad idea to use the command pattern here. Your IView is very implementation specific because it has a prescribed number of controls that should have a Click event (I know it is an example, but still...).
A simple implementation of the command pattern would be to let IView have a List<Action> that is supplied by the presenter, and let a specific implementation of a view decide how to fire these actions, e.g. by doing
this.button1.Click += (sender, e) => this.Actions[0]();
A mock object would not need to have a Click event (which may not even be supported by Moq, I'm not sure). You could just have it fire one of its actions.
I Changed my IButton interface to this one:
public interface IButton : IControl
{
voie SUbscribeOnClick(EventHandler click);
}
public class ButtonStub : IButton
{
EventHandler click;
public bool Enabled { get; set; }
public void SubscribeOnClick(EventHandler click)
{
this.click = click;
}
public string Text { get; set; }
public void RaiseClickEvent()
{
click(this, EventArgs.Empty);
}
}
This way I was able to make stub class which have private event where I can subscribe and after that call method which fires event when needed.
Related
I want to follow good practices design patterns when developing WinForms applications.
I have a UserControl with a button "Add" to open a new Form where de user can search Employees. How i can organize my code?
If you use WinForms you should use MVP (Model-View-Presenter) design pattern. In this case each view has own ISomethingView which contains the properties and the events, for example:
public interface IBaseView
{
void Show();
void Close();
}
public interface ILoginView : IBaseView
{
string Login { get; }
string Password {get; }
event EventHandler SignIn { get; }
}
And now your UserControl must implemented this interface.
Also for each view you have to create a presenter which is responsible for communication between the view and a business logic:
public LoginPresenter
{
// private variables
public LoginPresenter(ILoginView loginView, IOtherView otherView)
{
this.loginView = loginView;
this.otherView = otherView;
this.loginView.SignUp += OnSignUp;
}
private void OnSignUp(object sender, EventArgs eventArgs)
{
if (this.authService.Login(this.loginView.UserName, this.loginView.Password))
{
this.loginView.Close();
this.otherView.Show();
}
}
}
You can use DI container to resolve all I*Vies, for example:
public class LoginUserControl : UserControl, ILoginView
{
public LoginUserControl()
{
this.loginPresenter = new LoginPresenter(this, DIContainer.Resolve<IOtherView>());
}
}
I have a class library that has a number of classes.
Any of these classes should be able to send a message (string) to the client at any point of time . I want to have a Generic Event that can be raised from a number of classes. I don't want a separate event for each class.
Something like this:
public class GenericEvent
{
// Here I have an event.
}
public class LibClass1
{
//Raise event here.
}
public class LibClass2
{
//Raise event here
}
public class Client
{
//Subscribe to the event here
}
Is this the right approach? If yes, how can it be achieved? The examples I looked up all have a separate event for each class.
It depends on what this event is and use cases, but one of the options is to use inheritance:
public class GenericEvent
{
// Here I have an event.
protected void RaiseEvent();
}
public class LibClass1 : GenericEvent
{
public voidDoSomethingAndRaiseEvent()
{
// ...
RaiseEvent();
}
}
This is how INotifiPropertyChanged is usually implemented.
If inheritance is impossible and you're using aggregation, LibClass1 and LibClass2 should act as some facade/decorator for GenericEvent: they must have their own event, which re-directs calls to GenericEvent's event and method(-s) to raise it:
public class GenericEvent
{
public event EventHandler SomeEvent;
// ...
}
public class LibClass1
{
private readonly GenericEvent _ge;
// ...
public event EventHandler SomeEvent
{
add { _ge.SomeEvent += value; }
remove { _ge.SomeEvent -= value; }
}
public void DoSomethingAndRaiseEvent()
{
// ...
SomeEvent?.Invoke(this, EventArgs.Emtpy);
}
}
public class MyEventArgs : EventArgs
{
// class members
}
public abstract class Lib
{
public event EventHandler ShapeChanged;
public virtual void OnShapeChanged(MyEventArgs e)
{
if (ShapeChanged != null)
{
ShapeChanged(this, e);
}
}
}
public class LibClass1 : Lib
{
//Raise event here.
}
public class LibClass2 : Lib
{
//Raise event here
}
static void Main(string[] args)
{
LibClass1 lib1 = new LibClass1();
LibClass2 lib2 = new LibClass2();
lib1.ShapeChanged += Lib1_ShapeChanged;
lib2.ShapeChanged += Lib1_ShapeChanged;
lib1.OnShapeChanged(new MyEventArgs());
}
Here full example create an abstract class in which you have the event.
I would work with inheritance. For example:
public class ParentClass : Form
{
public ParentClass() {
this.FormClosed += sendString;
}
private void sendString(object sender, FormClosedEventArgs e)
{
throw new NotImplementedException();
}
}
public class GenericEvent : ParentClass { }
public class LibClass1 : ParentClass { }
public class LibClass2 : ParentClass { }
public class Client : ParentClass { }
Now all of you Clases have the event of the ParentClass.
I have another approach.
Derive all of your classes from one single base class. (of course any library do that, .net or MFC or Qt or java framework).
you have a single event "event 1" in base class. In that event1 handler, raise "event 2".
Subscribe all your child classes to the "event2" of parent class and handle your business in respective child classes.
My interface has an event that don't has an arguments
public interface IMyInterface
{
event EventHandler OnSomethingHappened;
}
Here is how I am implementing it.
public class MyBaseClass : IMyInterface
{
private event EventHandler onSomethingHappened;
public event EventHandler OnSomethingHappened
{
add
{
onSomethingHappened-= value;
onSomethingHappened+= value;
}
remove
{
onSomethingHappened-= value;
}
}
}
But somehwere else when I try to use it as follows
if ( MyBaseClassInstance.OnSomethingHappened != null )
MyBaseClassInstance.OnSomethingHappened();
I get following compilation error
The event 'ConsoleApplication1.IMyInterface.OnSomethingHappened' can
only appear on the left hand side of += or -=
What am I doing wrong?
This is how your code might look:
public interface IMyInterface
{
event EventHandler OnSomethingHappened;
}
//implement the interface
public class MyBaseClass : IMyInterface
{
public event EventHandler OnSomethingHappened;
public void DoSomeLogicWhichRaisesTheEvent()
{
if (OnSomethingHappened != null)
{
MyBaseClass sender = this;
var eventArgs = new EventArgs();
//let all subscibers to event know that the event happened
OnSomethingHappened(sender, eventArgs);
}
}
}
public class ConsumerClass
{
private IMyInterface myBaseClassInstance;
public ConsumerClass()
{
myBaseClassInstance = new MyBaseClass();
//attach to the event
myBaseClassInstance.OnSomethingHappened += MyBaseClassInstance_OnSomethingHappened;
}
private void MyBaseClassInstance_OnSomethingHappened(object sender, EventArgs e)
{
//react to the raised event
throw new NotImplementedException();
}
}
As you can see you need to implement the IMyInterface interface, and when MyBaseClass needs to raise the event you call OnSomethingHappened(sender, eventArgs);
ConsumerClass is where you need to consume, or to do something, as a reaction to the raised event.
You may consider to rename MyBaseClass to some other name, without 'Base' in it, because it is not an abstract class.
I just started with C# and MVP design pattern.
I'm in doubt about concrete implementation when it comes to event handling. I'm aware of that, view shouldn't know about presenter and presenter should control a view through view interface.
Let's say I have 2 text boxes and would like to check for errors. If an error occurs I want to change text box Text property. Is it wrong approach to create one EventHandler and use sender object to verify witch text box is user currently using?
Something like:
IView:
interface IMainView
{
event KeyPressEventHandler KeyPressed;
}
View:
public partial class MainView : Form, IMainView
{
public frmInterakcija()
{
InitializeComponent();
this.textBox1.Name = "textBox1";
this.textBox2.Name = "textBox2";
new MainPresenter();
Bind();
}
private void Bind()
{
this.textBox1.KeyPress += KeyPressed;
this.textBox2.KeyPress += KeyPressed;
}
}
Presenter:
class MainPresenter
{
private IMainView _view;
public MainPresenter(IMainView view)
{
_view = view;
this.initialize();
}
public void initialize()
{
_view.KeyPressed += _view_textBoxKeyPressed;
}
public void _view_textBoxKeyPressed(object sender, EventArgs e)
{
if (sender.GetType() == typeof(TextBox))
{
TextBox textBox = (TextBox)sender;
if (textBox.Name.Equals("textbox1")
{...} // Do validation/changes on textbox1
else ...
}
}
}
Or instead of this above I should create event handler for every textbox I have and update/handle errors through properties? (this will make my code redundant I guess)
What would be right approach?
IMHO the presenter should be unaware of view specific objects (example textbox in your code). That kind of logic should not be in presenter. And presenter must not know about the Ids of controls in the UI, that's even worse. Remember one of the benefits of this should be that you can test the presenter by mocking the view, if you have UI specific code you won't be able to unit test the presenter.
It does seem like two different events to me since you are doing different logic. I'd raise two different events and one would do validation, the other would do its own logic. The presenter won't have to check if the sender is textbox or the id of the textbox. Also what if you have another textbox, you'll need another if condition in this current implementation.
Also, in the view, it should be new MainPresenter(this);
Your presenter should absolutely not have view-specific types in it (e.g. controls, events, etc.) since these are hard to fake when it comes time to test the presenter's logic. Instead, you should have something like the following.
IView:
interface IMainView
{
// give these better names based on what they actually represent (e.g. FirstName and LastName)
// you could also add setters if you needed to modify their values from the presenter
string Text1 { get; }
string Text2 { get; }
// provide a way to bubble up validation errors to the UI
string ErrorMessage { get; set; }
}
Presenter:
class MainPresenter
{
private IMainView _view;
public MainPresenter(IMainView view)
{
_view = view;
}
public void ValidateText1()
{
if (/* some validation is false */)
{
_view.ErrorMessage = "Text1 isn't valid";
}
}
public void ValidateText2()
{
if (/* some validation is false */)
{
_view.ErrorMessage = "Text2 isn't valid";
}
}
}
View:
public partial class MainView : Form, IMainView
{
var readonly MainPresenter _presenter;
public frmInterakcija()
{
InitializeComponent();
_presenter = new MainPresenter(this);
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs eventArgs)
{
_presenter.ValidateText1();
}
private void textBox2_KeyPress(object sender, KeyPressEventArgs eventArgs)
{
_presenter.ValidateText2();
}
#region Implementation of IMainView
public string Text1
{
get { return textBox1.Text; }
}
public string Text2
{
get { return textBox2.Text; }
}
public string ErrorMessage
{
get { return labelErrorMessage.Text; }
set { labelErrorMessage.Text = value; }
}
#endregion
}
I am creating a gui widget a dll library, a class that derives from a FORM (I thought about usercontrol but it doesn't have built in properties like Opacity and some more that i need).
Because I don't want to expose to the user of this control all the standard methods and propertis that this derived class will inherit, I've created a nothe class "middle-man" that should encapsulate and expose only the needed methos to the user of this dll.
The problem is exposing the events.
This is an abstract example:
class Class1
{
Class2 theClass2;
public Class1()
{
theClass2 = new Class2();
theClass2. += new EventHandler(theClass3_EventHandler);
theClass2.TriggerEvent();
}
void theClass3_EventHandler(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
class Class2
{
Class3 theClass3;
public Class2()
{
theClass3 = new Class3();
}
public void TriggerEvent()
{
theClass3.Trigger();
}
class Class3
{
public event EventHandler theEvent;
public void Trigger()
{
if (this.theEvent != null)
theEvent(this, new EventArgs());
}
}
}
public event EventHandler theEvent {
add {
SomeNestedClass.theEvent += value;
}
remove {
SomeNestedClass.theEvent -= value;
}
}
First of all, inheritance is a is-a relationship. That means that everything that a Form can do should all sub classes be able to do. Since this is not the case for you, you should not derive the form.
As for the events. You need to redefine them in your "middle-man" class. And in that class simply subscribe on the events from the form and trigger them in the handler methods.
public class MyCoolControl : Control
{
private Form _customForm;
public MyCoonControl()
{
_customForm.Clicked += (source, e) => Clicked(source,e);
}
public event EventHandler Clicked = delegate {};
}