How to set control state in MVP - c#

I want to disable button(or other control) when user can't raise event. What is the best way to do this? View handles that or presenter should pass value by property in view and then view will update control's state.
For example if previous query is not finished user shouldn't start new.
Option 1:
interface IView
{
event EventHandler Event;
}
class View : IView
{
private readonly Button _button;
public event EventHandler Event;
public void button_Click(object sender, EventArgs e)
{
_button.Enabled = false;
if(Event != null)
{
Event(this, EventArgs.Empty);
}
_button.Enabled = true;
}
}
class Presenter
{
public void View_Event(object sender, EventArgs e)
{
// code...
}
}
Option 2:
interface IView
{
event EventHandler Event;
bool CanRaiseEvent { set; }
}
class View : IView
{
private readonly Button _button;
public event EventHandler Event;
public bool CanRaiseEvent
{
set
{
_button.Enabled = value;
}
}
public void button_Click(object sender, EventArgs e)
{
if (Event != null)
{
Event(this, EventArgs.Empty);
}
}
}
class Presenter
{
private readonly IView _view;
public void View_Event(object sender, EventArgs e)
{
_view.CanRaiseEvent = false;
// code...
_view.CanRaiseEvent = true;
}
}
I know that i should check in presenter query's status before executing next query but I want to inform view that user shouldn't even try.

Two 'litmus' tests I use for MVP design are: 1) Is the logic testable? and 2) Could I replace the concrete view and the application still work?
From this perspective, option 2 looks the more attractive.

Related

How to execute code when a property is changed using INotifyPropertyChanged

I´ve started learning only recently so this is a newbie question.
Maybe someone could help me out in regards to what I´d have to do differently for my code to work.
In short: I have a class that inherits from INotifyPropertyChanged (which I´v tried to implement according to MSDN). When I press a button I want to change a variable in this class which in turn should raise a PropertyChanged Event. When the event is raised some code should be executed.
My ValueChanged class:
public class ValueChange : INotifyPropertyChanged
{
public ValueChange()
{
_size = 1;
}
private int _size;
public int Size
{
get
{
return _size;
}
set
{
_size = value;
OnPropertyRaised("Size");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyRaised([CallerMemberName] string name = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
My event listeners:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
ValueChange test = new ValueChange();
test.Size = 10;
}
private void PropertyChanged(object sender, PropertyChangedEventArgs args)
{
switch (args.PropertyName)
{
case "Size":
// txtbox is just some textbox in my UI
txtbox.Text = "some text";
// This is merely a placeholder as I´d like to be able to execute any code in here
break;
}
}
}
There are a few issues with the code.
You are creating a new instance of the ValueChange class every time you click.
You are not subscribing to PropertyChanged event.
Although this will fix your code, is there a reason you are using PropertyChanged here instead of executing your code directly in the Button_Click event handler? PropertyChanged is usually used when binding, it is rarely used directly as you are doing here.
public partial class MainWindow : Window
{
ValueChange test = new ValueChange();
public MainWindow()
{
test.PropertyChanged += PropertyChanged;
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
test.Size = 10;
}
private void PropertyChanged(object sender, PropertyChangedEventArgs args)
{
switch (args.PropertyName)
{
case "Size":
// txtbox is just some textbox in my UI
txtbox.Text = "some text";
// This is merely a placeholder as I´d like to be able to execute any code in here
break;
}
}
}

C# Event name is null

I have a WinForms application wherein I have my main application with a separate class that is part of the solution. In the class which is defining a User control with Dev Express buttons, I have defined my event delegate, event, method and eventargs.
In the main program, i have defined my listener.
I am getting a null value in my event method and cannot see why. I have reviewed this a number of times and as far as I can see, it is completely correct.
I would appreciate any comments/corrections that would be useful here.
This is the code in my class.
public partial class XtraUserControl1 : XtraUserControl, IAnyControlEdit
{
public delegate void ButtonClickedEventHandler(object sender, ClickEventArgs e);
public event ButtonClickedEventHandler ButtonClicked;
public XtraUserControl1()
{
InitializeComponent();
}
public void OnButtonClicked(ClickEventArgs e)
{
if (ButtonClicked != null)
{
ButtonClicked(this, e);
}
}
public class ClickEventArgs : EventArgs
{
public readonly SimpleButton buttonClicked;
public ClickEventArgs(SimpleButton button)
{
this.buttonClicked = button;
}
}
This is the main code where I have defined the listener.
private void frmEHHeaders_Load(object sender, EventArgs e)
{
// Create the button group from the User Control XtraUserControl1 and add it to the grid repository
btnGroup = new User_Controls.XtraUserControl1();
RepositoryItemAnyControl riAny = new RepositoryItemAnyControl();
riAny.Control = btnGroup;
grdEHHeaders.RepositoryItems.Add(riAny);
colButtons.ColumnEdit = riAny;
// Add event handlers
this.grdEHHeaders.Views[0].MouseDown += gridView1_MouseDown;
gridView1.CustomRowCellEdit += GridView1_CustomRowCellEdit;
// Listener for the button class
btnGroup.ButtonClicked += new User_Controls.XtraUserControl1.ButtonClickedEventHandler(btnGroup_ButtonClicked);
GetData();
}
private void btnGroup_ButtonClicked(object sender, User_Controls.XtraUserControl1.ClickEventArgs e )
{
SimpleButton myButton = e.buttonClicked;
MessageBox.Show("You clicked " + myButton.Text);
}

checkbox.Checked dosent update on other forms

I have 2 forms, UserInterface and Client I'm passing checkbox2.Checked info to Client but it only works however it was at launch. When I tick or untick and close and reopenClient it wont notice the change.
Modifiers is Public on checkbox2 at UserInterface form.
Here is Client code:
public partial class Client : Form
{
private UserInterface ui1;
public Client()
{
InitializeComponent();
}
public void CheckBoxCheck()
{
if (ui1.checkBox2.Checked == true)
{
MessageBox.Show("true");
}
else
{
MessageBox.Show("false");
}
}
}
If the checkbox is ticked at launch Client will show "true" but if I click it (untick) and run Client it will still show "true".
What do I need to add or modify so checkbox2 will be updated in realtime. Thank you.
Note: I'm pretty new with coding, explanations are appreciated.
I'll be building on noMad17's answer, you have to subscribe to your CheckBox event in your UserInterface form. But the change is that now we will send the CheckBox that was clicked in the event. So this code is for your UserInterface form:
public event EventHandler SomeEvent;
protected void OnSomeEvent(object sender, EventArgs e)
{
EventHandler eh = SomeEvent;
if(eh != null)
{
eh(sender, e);
}
}
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
OnSomeEvent(sender, e);
}
Now for the Client, it needs to know what a UserInterface is so we have to pass UserInterface to the Client in the constructor, otherwise it won't initialize. Also here we are gonna work out the CheckBox event that the parent form is gonna give us. And in the end we have to unsubscribe the event. So this code is for your Client:
public partial class Client : Form
{
private UserInterface ui1;
public Client(UserInterface ui1)
{
InitializeComponent();
this.ui1 = ui1;
ui1.SomeEvent += UI1_SomeEvent;
}
private void UI1_SomeEvent(object sender, EventArgs e)
{
//Your code...
CheckBox c = sender as CheckBox;
if(c.Checked == true)
{
MessageBox.Show("true");
}
else
{
MessageBox.Show("false");
}
}
private void Client_FormClosing(object sender, FormClosingEventArgs e)
{
ui1.SomeEvent -= UI1_SomeEvent;
}
}
Your Forms should be connected. It looks like ui1 is a different instance of UserInterface form.
There are different approaches to pass the data between forms and it depends on your demands.
For instance you could create UserInterface form inside of Client. And use the Show() method to show it.
You should probably be making use of the Checkbox.Checked event inside UserInterface class and then fire a custom event that your Client can subscribe to.
public event EventHandler<EventArgs> CheckboxCheckedChanged;
protected void OnCheckboxCheckedChanged(EventArgs e)
{
if (CheckboxCheckedChanged != null)
CheckboxCheckedChanged(this, e);
}
private void checkbox2_CheckedChanged(object sender, EventArgs e)
{
OnCheckboxCheckedChanged(e);
}
And then in Client:
ui1.CheckboxCheckedChanged += ui1_CheckboxCheckedChanged;
private void ui1_CheckboxCheckedChanged(object sender, CheckBoxEventArgs e)
{
// Your code here
}

What are techniques in ASP for communication from usercontrol to parent page?

I have having some trouble with communication from a usercontrol to the main page. The order in which events are raised means that the action on the user control occurs too late in the post back to have an effect on the main page.
For example, I have a button on a user control which, when pressed, raises a custom event that is being listened for on the main page. When the button is pressed the postback order is:
page_load - on the main page
page_load - on the usercontrol (the user control is loaded programitically by the main page page_load)
The button call back on the user control
The event call back method on the main page
By this point, it seems it is too late for anything the event call back method does to have any effect on the rendered page, for example I am trying to use it to change the usercontrol that is being displayed.
What other techniques can be used for this kind of communication?
Relevant code
Main page:
public string LastLoadedControl
{
get
{
return Session["LastLoaded"] as string;
}
set
{
Session["LastLoaded"] = value;
}
}
private void LoadUserControl()
{
string controlPath = LastLoadedControl;
ContentPlaceholder.Controls.Clear();
if (string.IsNullOrEmpty(controlPath))
controlPath = Utils.Paths.USERCTRL_BASE + "Main.ascx";
Control uc = Page.LoadControl(controlPath);
ContentPlaceholder.Controls.Add(uc);
}
protected void Page_Load(object sender, EventArgs e)
{
LoadUserControl();
if (!IsPostBack)
Utils.Events.redirectPage += Events_redirectPage;
}
private void Events_redirectPage(string path)
{
if (path.Equals("Main"))
{
//Session.Clear();
//Session.Abandon();
}
else LastLoadedControl = Paths.USERCTRL_BASE + path + ".ascx"
LoadUserControl();
}
User control
protected void profileBtn_Click(object sender, EventArgs e)
{
Utils.Events.triggerRedirectPage("Login");
}
Event
public class Events
{
public delegate void redirectEvent(string path);
public static event redirectEvent redirectPage;
public static void triggerRedirectPage(String path)
{
if (Utils.Events.redirectPage != null)
Utils.Events.redirectPage(path);
}
}
There are two approaches that you can follow.
Approach 1:
public interface IEventProvider
{
void TriggerEvent();
}
public class YourPage: Page, IEventProvider
{
// Other page methods
public void TriggerEvent()
{
// Your Implementation
}
}
public class YourUserControl : WebUserControl
{
protected void profileBtn_Click(object sender, EventArgs e)
{
IEventProvider eventProvider = this.Page as IEventProvider;
if(eventProvider != null)
eventProvider.TriggerEvent();
}
}
Approach 2:
public interface IEventProvider
{
// This does not have to be a boolean. You can use a string / enum / anything that suits your implementation
bool Trigger {get; set;}
}
public class YourPage: Page, IEventProvider
{
// Other page methods
protected override void OnLoadComplete(EventArgs e)
{
// This will be raised when all the events have fired for all the controls in the page.
if(this.Trigger)
TriggerEvent();
}
protected void TriggerEvent()
{
// Your code here
}
public bool Trigger
{
get;
set;
}
}
public class YourUserControl : WebUserControl
{
protected void profileBtn_Click(object sender, EventArgs e)
{
IEventProvider eventProvider = this.Page as IEventProvider;
if(eventProvider != null)
eventProvider.Trigger = true;
}
}

How can I pass addition parameters to my centralized event handlers?

In a WPF application, I've got my events centralized in one class like this:
public class EventFactory
{
public static void Button_Edit_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("you clicked edit");
}
public static void Button_Add_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("you clicked add");
}
}
so that I can reuse them in many Windows like this:
public Window1()
{
InitializeComponent();
ButtonEdit.Click += EventFactory.Button_Edit_Click;
ButtonAdd.Click += EventFactory.Button_Add_Click;
}
This works fine, but now I want the events to act on the Windows which call them which I was able to do when the event handlers were simply in the code-behind for each window.
How can I e.g. inject a window object into the event handler so that that event handler can directly manipulate it, something like this:
ButtonEdit.Click += EventFactory.Button_Edit_Click(this);
One way:
ButtonEdit.Click += EventFactory.ForConsumer<Window1>().Button_Edit_Click;
In other words, turn your factory class into an actual factory that creates objects based on some context. In this case, the context is the object consuming the events.
Another way:
public static void Button_Edit_Click(object sender, RoutedEventArgs e)
{
Window window = Window.GetWindow(sender as DependencyObject);
MessageBox.Show("you clicked edit");
}
I'm not particularly fond of either of these approaches, but there you go.
You can try something like this:
public class CommonEventHandler
{
private CommonEventHandler() { }
private object Context { get; set; }
public static EventHandler CreateShowHandlerFor(object context)
{
CommonEventHandler handler = new CommonEventHandler();
handler.Context = context;
return new EventHandler(handler.HandleGenericShow);
}
private void HandleGenericShow(object sender, EventArgs e)
{
Console.WriteLine(this.Context);
}
}
class Program
{
static void Main(string[] args)
{
EventHandler show5 = CommonEventHandler.CreateShowHandlerFor(5);
EventHandler show7 = CommonEventHandler.CreateShowHandlerFor(7);
show5(null, EventArgs.Empty);
Console.WriteLine("===");
show7(null, EventArgs.Empty);
}
}
You need to adapt the types to suit your needs but it shows the general idea.

Categories