Why is the Binding Format event called twice? - c#

I am playing around with data binding and noticed that the Binding Format is called twice upon loading the form in the code below. I thought it would only happen once when the test class TextBoxText property is fist bound to textbox1. Is this normal? If not, then what can I do to prevent it? Note, when I press button1 and it changes the TextBoxText property of the test class, the format event fires once as expected.
public partial class Form1 : Form
{
Test _test = new Test();
public Form1()
{
InitializeComponent();
Binding binding = new Binding("Text", _test, "TextBoxText");
binding.Format += new ConvertEventHandler(Binding_Format);
this.textBox1.DataBindings.Add(binding);
}
private void Binding_Format(object sender, ConvertEventArgs e)
{
Debug.WriteLine("Format");
}
private void button1_Click(object sender, EventArgs e)
{
_test.TextBoxText = "test1";
}
}
class Test : INotifyPropertyChanged
{
private string _text;
public string TextBoxText
{
get { return _text; }
set
{
_text = value;
OnPropertyChanged(new PropertyChangedEventArgs("TextBoxText"));
}
}
private void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChanged(this, e);
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion

The simple answer: "Because that is the way Microsoft implemented it".
The goal is to just respond to the event... whenever it happens... however often it occurs. We can't make any assumptions. There are cases where you might get called six times on the same event.
We just have to roll with it and continue to be awesome.

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);
}

How to set control state in MVP

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.

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
}

I am trying to raise event at UserControl, and catch it at Main program, But the event always return null

I am trying to raise a event in one of classes of userControl, and Fire it in the Main class. I tried two different ways to fire this event, one of them works, But I still want to know why other way cannot work, and how to fix it.
My userContol class:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
return;
}
Class1 c = new Class1();
Thread accept = new Thread(
() =>
{
c.connection();
}
);
accept.Start();
}
}
And the Class1:
public class Class1
{
public delegate void myhandler(object sender, EventArgs e);
public event myhandler test;
public Class1()
{
}
public void connection()
{
test(this, new EventArgs());
}
}
In the Main, I just simply add into referent, and add
xmlns:my="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
then I try to subscribe this event in the main
public partial class SurfaceWindow1 : SurfaceWindow
{
/// <summary>
/// Default constructor.
/// </summary>
public SurfaceWindow1()
{
InitializeComponent();
Class1 c = new Class1();
c.test+=new Class1.myhandler(c_test);
// Add handlers for window availability events
AddWindowAvailabilityHandlers();
}
public void c_test(object sender, EventArgs e)
{
MessageBox.Show("fire");
}
}
If I only raise this event not into thread, it works fine, but If I try to let it raise in this thread, this test event only return null, and shows:
Object reference not set to an instance of an object.
looks like I did not subscribe it ever. So How to fix it if I must use it in thread.
This is a good example of what you really shouldn't be doing. You are trying to subscribe to an event of a class that is "owned" by another class. You are basically digging through the type hierarchy to find the event you want. This goes against good design.
Especially in UI applications there is a design concept called Event Bubbling. The type that owns the original object raising the event handles that event. In the handling of that event, it raises its own duplicate event. Here is a short-ish program that shows the concept:
public class RootEventClass
{
public event EventHandler SomeKindOfEvent;
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
Console.WriteLine("Root Event Firing");
OnSomeKindOfEvent(this, EventArgs.Empty);
}
}
public class FirstOwnerClass
{
private RootEventClass _rootClass;
public event EventHandler SomeKindOfEvent;
public FirstOwnerClass()
{
_rootClass = new RootEventClass();
_rootClass.SomeKindOfEvent += _rootClass_SomeKindOfEvent;
}
void _rootClass_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("First Owner Class Handling Root Owner Event");
OnSomeKindOfEvent(this, e);
}
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
_rootClass.RaiseEvent();
}
}
public class SecondOwnerClass
{
private FirstOwnerClass _firstClass;
public event EventHandler SomeKindOfEvent;
public SecondOwnerClass()
{
_firstClass = new FirstOwnerClass();
_firstClass.SomeKindOfEvent +=_firstClass_SomeKindOfEvent;
}
void _firstClass_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("Second Owner Class Handling First Owner Event");
OnSomeKindOfEvent(this, e);
}
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
_firstClass.RaiseEvent();
}
}
public class Program
{
public static void Main(string[] args)
{
SecondOwnerClass secondOwner = new SecondOwnerClass();
secondOwner.SomeKindOfEvent += secondOwner_SomeKindOfEvent;
secondOwner.RaiseEvent();
Console.ReadKey(true);
}
static void secondOwner_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("Got an event from the second owner defined in main");
}
}
If you run this program, you will get the following output:
Root Event Firing
First Owner Class Handling Root Owner Event
Second Owner Class Handling First Owner Event
Got an event from the second owner defined in main
So what is happening here. The Main method defines a SecondOwner object and then tells it to raise an event, which just passes it up the ownership chain to the root object. The magic is the event bubbling. The event is intercepted by each owning class and passed on. This way it can decide to pass it on or not.
Also, the Main method only needs to know about the events created in the SecondOwner class, it doesn't have to dig through SecondOwner, FirstOwner and finally RootEventClass.
Its an easy concept to grasp really, don't force your users (or yourself) to dig through types and ownership to get to an event, if users of the class will need that event, duplicate the event and bubble it.

Categories