EventHandler is always null? - c#

I want to create a event and subscribe is on another ViewModel. The event handler is always getting null on the first ViewModel.
In the first Viewmodel I declared Event and raised as follows
public event EventHandler EditSearchChanged;
and raised as
if (EditSearchChanged != null)
{
EditSearchChanged(this, null);
}
In the second Viewmodel,I have declared a property of first Viewmodel.
private EditTileViewModel editTileVM;
public EditTileViewModel EditTileVM
{
get
{
return editTileVM ?? (editTileVM = new EditTileViewModel());
}
set
{
editTileVM = value;
RaisePropertyChanged();
}
}
and subscribe the event as follows
EditTileVM.EditSearchChanged += EditTileVM_EditSearchChanged;
private void EditTileVM_EditSearchChanged(object sender, EventArgs e)
{
this.EditTileVM = (sender as EditTileViewModel);
}
Debugger Result

It happens as you create another new instance of ViewModel in the following property:
private EditTileViewModel editTileVM;
public EditTileViewModel EditTileVM
{
get
{
return editTileVM ?? (editTileVM = new EditTileViewModel());
}
set
{
editTileVM = value;
RaisePropertyChanged();
}
}
So there are two instances of EditViewModel.
I suggest you to use EventAggregator pattern between two viewModels from Prism framework:
// Subscribe
eventAggregator.GetEvent<CloseAppliactionMessage>().Subscribe(ExitMethod);
// Broadcast
eventAggregator.GetEvent<CloseAppliactionMessage>().Publish();
Please, see a very good tutorial of Rachel Lim about simplified Event Aggregator pattern.
Or use MVVM Light messenger:
//Subscribe
Messenger.Default.Register<CloseAppliactionMessage>(ExitMethod);
// Broadcast
Messenger.Default.Send<CloseAppliactionMessage

Related

c# DataChanged event does trigger on a windows form (Desktop Application)

I have a form, I select some checkboxes, edit some text field, select from a combobox etc. then I click Exit. Based on the fact that "Data has been changed ??" I wish to perform actions. The problem is I can't get the event work :
private void DataChanged(object sender, EventArgs e)
{
MessageBox.Show("Data is changed", "debug");
isDataSaved = false;
}
When is this method called, how do I make it work? Is this supposed to get fired when the form's fields have some data i.e filL a text box ?
I dont really get the API: DataChanged event
Note: I'm following Mike Murach C# 5th edition chapter 10 example.
Edit (exact words from book):
Generate an event handler named DataChanged for the
SelectedIndexChanged event of the XXXX Name combo box. Then , wire
this event handler to the TextChanged event of the YYYYY Method label
and add the code to this event handler so it sets the isDataSaved
variable to false
When I double click on the commbo box the generated event handler it is not named DataChanged but cboNames_SelectedIndexChanged... (is this a book screw up or me total noob ? PS: There is no .. 'database' in the project)
Personally I mostly use databinding these days to get notified of changes in data.
A data holder class, which implements INotifyPropertyChanged. This interface gives you the possibility to get notified when the value of a property changes.
public class SomeData: INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private void SetProperty<T>(ref T field, T value, [CallerMemberName] string name = "") {
if (!EqualityComparer<T>.Default.Equals(field, value)) {
field = value;
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(name));
}
}
}
private boolean _someBoolean;
public int SomeBoolean {
get { return _someBoolean; }
set {
SetProperty(ref _someBoolean, value);
}
}
private string _someString;
public string SomeString {
get { return _someString; }
set {
SetProperty(ref _someString, value);
}
}
// etc
}
Now our form, which uses the data class and it's INotifyPropertyChanged implementation to get notified when a change in data occurs.
public partial class SomeForm: Form {
private SomeData _data;
private void LoadData() {
_data = new SomeData();
_data.PropertyChanged += Data_PropertyChanged;
}
private void SaveData() {
// TODO: Save data
}
private void AddDataBindings() {
checkbox1.DataBindings.Add("Checked", _data, "SomeBoolean");
textbox1.DataBindings.Add("Text", _data, "SomeString");
// add other
}
private void Data_PropertyChanged(object sender, PropertyChangedEventArgs e) {
// Here you can add actions that must be triggered when some data changes.
if (e.PropertyName == "SomeBoolean") {
// Do something when some-boolean property changes
}
// Set is-changed-boolean to true to 'remember' that something has changed.
_isChanged = true;
// Give message
MessageBox.Show(string.Format("Data changed, property {0}", e.PropertyName));
}
private bool _isChanged = false;
protected void Form_Closed(object sender, EventArgs e) {
// If data is changed, save it
if (_isChanged) {
SaveData();
}
}
}
Your problem is not known where the method DataChanged use and how. I have a suggestion for you that is use Focus Activated in properties.Add datachanged printing method Activated
good luck.
You must make properties this like

Polling an object's public variable

I would like to notify a program immediately when there is a change in a bool variable that is a public variable of an object. For example;
say, an instance of class conn is created within a windows form application.
there is a Ready variable, a public variable of the class conn is present.
I would like to get notified whenever there is a change in this variable.
I did a quick research to solve this problem within stackoverflow but the answers suggested the use of property, which, I think is not suitable for my application.
I will assume you are referring to a field when you say public variable.
With few exceptions, it is preferable to not have public fields in C# classes, but rather private fields with public accessors:
class BadClass
{
public int Value; // <- NOT preferred
}
class GoodClass
{
private int value;
public int Value
{
get { return this.value; }
set { this.value = value; }
}
}
One of the reasons to structure your code this way is so you can do more than one thing in the property's getter and setters. An example that applies to your scenario is property change notification:
class GoodClass : INotifyPropertyChanged
{
private int value;
public int Value
{
get { return this.value; }
set
{
this.value = value;
this.OnPropertyChanged("Value");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(name);
}
}
}
If you were to implement your class like this, you could use it this way:
void SomeMethod()
{
var instance = new GoodClass();
instance.PropertyChanged += this.OnPropertyChanged;
}
void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Value")
{
// Do something here.
}
}
If you change the Value property, not only will it change the value of the underlying field, but it will also raise the PropertyChanged event, and call your event handler.
You want to use the Observer pattern for this. The most straight forward way to do this in .NET is the event system. In the class conn, create an event:
public event EventHandler ReadyChanged;
and then when you create an instance of conn, subscribe to that event:
o.ReadyChanged += (s, e) =>
{
// do something
}
and then finally, when the flag changes in conn, fire the event via a new method named OnReadyChanged:
protected virtual void OnReadyChanged()
{
if (ReadyChanged != null) { ReadyChanged(this, new EventArgs()); }
}

How to write a Trigger?

I want my C# code to call an event whenever a value is assigned to my object.
How exactly would I need to go about that?
class MyClass {
ManualResetEvent mre;
public MyClass() {
mre = new ManualResetEvent(false);
Data = null;
}
public object Data { get; set; }
void DataSet(object sender, EventArgs e) {
Console.WriteLine("object Data has been set.");
mre.Set();
}
}
Delegates don't seem to be what I need. An event, maybe? How would I write such an event, if so?
MyClass mc;
void processA() {
mc = new MyClass();
mc.Data = GetDataFromLongProcess();
}
private object data;
public object Data {
get { return data;}
set {
if(value != data) {
data = value;
OnDataChanged();
}
}
}
protected virtual void OnDataChanged() {
EventHandler handler = DataChanged;
if(handler != null) handler(this, EventArgs.Empty);
}
public event EventHandler DataChanged;
then hook any code to the DataChanged event. For example:
MyClass mc = ...
mc.DataChanged += delegate {
Console.WriteLine("new data! wow!");
};
If you want to fire an event when your property is set, you would do something like this:
public event Action OnDataChanged;
protected object _data = null;
public object Data
{
get { return _data; }
set
{
_data = value;
if(OnDataChanged != null)
OnDataChanged();
}
}
Then you would simply wire up event handlers to your object like so:
mc = new MyClass();
mc.OnDataChanged += delegate() { Console.WriteLine("It changed!"); };
mc.Data = SomeValue();
I think you're on the right track with an event-based model. Also take a look at the Observer pattern (which is the basis for .Net delegates and events underneath it all, as I understand):
http://www.dofactory.com/Patterns/PatternObserver.aspx
But the bottom line, as the other useful answer so far (Mr. Gravell's implementation) indicates, you're going to have to have code IN the setter to get it hooked up. The only alternative would be to poll the value for changes, which just smells bad to me.
you could implement INotifyPropertyChanged (this is more or less a event) or you could take your class a Action (Trigger) and call this, whenn the property changed.
Just don't use automatic properties but a concrete setter and call your event/trigger from there.
Conceptually, you would define an event in your class, and in your property set blocks, you would invoke the event with the necessary arguments to determine what just happened.
public event SomeDelegateThatTakesIntAsParameter myEvent;
void SetData(int data)
{
if(myEvent!= null)
myEvent(data)
}

How to make own event handler?

I am making a windows forms project in C#, in which I made a class LabelX which inherits System.Windows.Forms.Label, then added a property Mass of float type
Now, my question is how can I handle, when value of Mass is changed.
e.g.:
When user enter value zero or less than zero
I want to fire a message that "Mass can't be zero or negative"
If I am interpreting this correctly, there are two parts to this. First, you need to detect invalid values and throw exceptions. Second, you need to raise an event when the property changes. This can be achieved as follows.
private float mass;
public float Mass
{
get
{
return this.mass;
}
set
{
if (value <= 0.0F)
{
throw new ArgumentOutOfRangeException("Mass cannot be zero or negative.");
}
if (this.mass != value)
{
this.mass = value;
OnMassChanged(EventArgs.Empty);
}
}
}
public event EventHandler MassChanged;
protected virtual void OnMassChanged(EventArgs args)
{
var handler = this.MassChanged;
if (handler != null)
{
handler(this, args);
}
}
To show a message if an invalid entry is made, you should put a try \ catch block around the call to set Mass and catch the ArgumentOutOfRangeException.
Try the following:
// Created an empty form with a LabelX control on it.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Added this event from the property manager.
private void labelX1_MassChanged(object sender, EventArgs e)
{
var label = (LabelX)sender;
if (label.Mass <= 0.0)
MessageBox.Show("Mass is less than or equal to 0");
}
}
public class LabelX : Label
{
private float _mass;
public float Mass
{
get { return _mass; }
set
{
if (!value.Equals(_mass))
{
_mass = value;
OnMassChanged(EventArgs.Empty);
}
}
}
public event EventHandler MassChanged;
protected virtual void OnMassChanged(EventArgs e)
{
if (MassChanged != null)
MassChanged(this, e);
}
}
Outside of your LabelX class, create the following class:
public class MassChangedEventArgs : EventArgs
{
public float Mass { get; private set; }
public MassChangedEventArgs(float mass)
{
this.Mass = mass;
}
}
Also outside of your LabelX class, create the following delegate. This will be your event handler.
public delegate void MassChangedEventHandler(object sender, MassChangedEventArgs e);
Within your LabelX class, create an event to broadcast:
public class LabelX
{
public event MassChangedEventHandler MassChanged;
//the rest of your code here...
}
You'll also want to create a private instance method that will fire your event.
public class LabelX
{
public event MassChangedEventHandler MassChanged;
private void OnMassChanged()
{
if(MassChanged!=null)
this.MassChanged(this, new MassChangedEventArgs(this.Mass));
}
//the rest of your code here...
}
Finally, whenever your Mass property changes, call OnMassChanged. For instance:
public class LabelX
{
private float mass;
public float Mass
{
get
{
return mass;
}
set
{
mass = value;
OnMassChanged();
}
}
public event MassChangedEventHandler MassChanged;
private void OnMassChanged()
{
if(MassChanged!=null)
this.MassChanged(this, new MassChangedEventArgs(this.Mass));
}
//the rest of your code here...
}
When you want to handle that event on a per-instance basis, you just have to register a listener with the MassChanged event of your underlying object and perform whatever actions are necessary.
Events are a common pattern used in the framework. The process typically involves defining a delegate to be used as the event handlers, declaring the event using the handler, defining methods to raise the event, then hooking up to the properties the logic to raise the event.
The message you describe is better done as an Exception but here's an example to define the MassChanged event.
// Define event args if you have additional
// information to pass to your event handlers
public class MassChangedEventArgs : EventArgs
{
public MassChangedEventArgs(int oldMass)
{
OldMass = oldMass;
}
public int OldMass { get; private set; }
}
public class SomeObject
{
// There's a generic event handler delegate that can be
// used so you only need to define the event arguments.
public event EventHandler<MassChangedEventArgs> MassChanged;
// Convenience method to raise the event
protected virtual void OnMassChanged(MassChangedEventArgs e)
{
if (MassChanged != null)
MassChanged(this, e);
}
public int Mass
{
get
{
return mass;
}
set
{
// Your checks here
if (value <= 0)
throw new ArgumentOutOfRangeException("Mass", "Mass can't be zero or negative");
// Should only raise the event if the new value is different
if (value != mass)
{
// Change the mass
MassChangedEventArgs e = new MassChangedEventArgs(mass);
mass = value;
// Raise the event
OnMassChanged(e);
}
}
}
private int mass;
}
After that, it's just a matter of registering handlers to the event and going from there.
I am quite sure you you would like to 'fire' an exception in your case.
This more of a validation logic issue such AOP code contracts concept.
But if you really like to create an event for it you have to at least:
1) create an event storage variable in your label class
public event EventHandler MassChanged;
2) in your property (note that you loose the ability to use code gen functions of c# 3 for
which 'auto' implement the field to store your Mass property value)
public bool Mass
{
get { return _mass; }
set {
// check if value is invalid (0 or less) && that event subscribers exist
if(value<=0 && MassChanged != null) { MassChanged(this, null); }
else // otherwise assign ...
{
_mass = value;
}
}
}
3) create an event handler of type EventHandler
Best to read the msdn article for events: link text
Again I am pretty sure you are not handling exceptions properly in the app
if you need an event for this. I mean there is nothing wrong but events are
usually not used as means of value validations.

Creating Events for change in some property value which is user defined

I am creating a custom control and i want to add some properties in it.
On few of the properties i want to create some events.
Say
if i have a property
public int Date {get; set;}
now if its value is changing i want to trigger a change event. SO how can i add event on this
Use a "normal" property rather than an automatic property, and raise the change event in the setter:
private int _date;
public int Date
{
get { return _date; }
set
{
if (value != _date)
{
_date = value;
// raise change event here
}
}
}
To raise the change event, if this is a standard INotifyPropertyChanged.PropertyChanged event:
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs("Date");
}
It's recommended practice to isolate this into an OnPropertyChanged method.
If you're raising a custom DateChanged event, the logic will be similar but with different names and event args.
The typical pattern to do this would be like so:
// declare the event
public event EventHandler DateChanged;
// declare backing field for the property
private int _date;
public int Date
{
get { return _date; }
set
{
// bool indicating whether the new value is indeed
// different from the old one
bool raiseEvent = _date != value;
// assign the value to the backing field
_date = value;
// raise the event if the value has changed
if (raiseEvent)
{
OnDateChanged(EventArgs.Empty);
}
}
}
protected virtual void OnDateChanged(EventArgs e)
{
EventHandler temp = this.DateChanged;
// make sure that there is an event handler attached
if (temp != null)
{
temp(this, e);
}
}
This example shows the implementation of an PropertyChanged event. For a PropertyChanging event, it's the same thing, but you raise the event before assigning the value in the property set accessor.
Well, you will need to define your event first of all, and a method to raise it.
Then you will need to switch away from an auto implemented property
private int _date;
public int Date
{
get {return _date;}
set
{
if(!_date.Equals(value))
//Raise event here
_date = value;
}
}
If you need some help with the events part, here is a tutorial that I wrote to give you the detail.
Also you can implement INotifyPropertyChanged interface and just raise an event in you property setter, here is full code sample that you can use and play with:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace ConsoleApplication1
{
class Foo : INotifyPropertyChanged
{
private object myProperty;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(sender, e);
}
}
public object MyProperty
{
get { return this.myProperty;}
set
{
if (this.myProperty != value)
{
this.myProperty = value;
this.OnPropertyChanged(this, new PropertyChangedEventArgs("MyPropery"));
}
}
}
}
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo();
foo.PropertyChanged += new PropertyChangedEventHandler(foo_PropertyChanged);
foo.MyProperty = "test";
}
static void foo_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine("raised");
}
}
}

Categories

Resources