I have a class which is inherited from context bound object. Class has attribute on some properties. When some property is changed, PostProcess(IMessage msg, IMessage msgReturn) raise an event and from the event again a new property with same attribute is fired. Second change should also call PostProcess, but it is not happening. Probably because, the object where second property is changed is not original .net object but MarshalByRefObject / ContextBoundObject / Proxy Object. My query is how to cast the proxy to original object. I tried casting and SynchonizationAttribute, but it does not help. Just to let you know the events are executing in Async manner so it does not block code execution, and both proxy and original object exist in same app domain.
I tried with two object, one holding reference of second, and when property of first is changed, it try to change property of second, but it did not invoke PostProcess.
Basically I need to make a tree where various objects are depending on property of other objects. And when any one property is changed, it should trigger its watcher, and this could spread like a chain untill no watcher is found. I am trying it with ContextBoundObject.
Sample:
public class PowerSwitch : ObjectBase
{
[Watchable]
public bool IsOn { get; set; }
public bool IsWorking { get; set; }
}
public class Bulb : ObjectBase
{
public Color Color { get; set; }
[Watchable]
public bool IsOn { get; set; }
protected override void Update(object sender, PropertyChangeEventArgs e)
{
((Bulb)this).IsOn = !((Bulb)this).IsOn;
//<-- b1.update should be called after this, but it is not
}
}
[Watchable]
public class ObjectBase : ContextBoundObject
{
public virtual void Watch(ObjectBase watch, string propertyName)
{
watch.Watcher.Add(this, propertyName);
}
protected virtual void Update(object sender,
PropertyChangeEventArgs e) { }
public Dictionary<ObjectBase, string> Watcher
= new Dictionary<ObjectBase, string>();
internal void NotifyWatcher(
PropertyChangeEventArgs propertyChangeEventArgs)
{
Watcher.Where(sk => sk.Value == propertyChangeEventArgs.Name)
.ToList()
.ForEach((item) =>
{
item.Key.Update(this, propertyChangeEventArgs);
});
}
}
Main method
PowerSwitch s1 = new PowerSwitch();
Bulb b1 = new Bulb();
b1.Watch(s1, "IsOn");
s1.IsOn = true; //<-- b1.update is called after this
Please suggest alternate or better way to implement what I want to achieve.
It looks like you're very close to the observer pattern, where Observers subscribe to status notifications on a Subject.
In that pattern, b1.IsOn = true would contain code that cycles through the Observers and notifies them of changes. I guess if you wanted to observe a lot of properties on one object, you could encapsulate the notification code. Then b1.IsOn could just have a single line that says something like:
this.SendNotification("IsOn", Value);
This seems a lot like what you're doing... If you read up on the pattern you might end up feeling a little more confident, and maybe you could make a few changes to standardize your code.
By the way, there is something built into .Net for this -- IObservable(T). I haven't used this, but it looks strong.
Related
I can't find a specific problem that matches mine, which I think has to do with the fact that I am creating a subclass of EventArgs with one argument, a string. When I try to compile, it seems to tell me that ScanInfoEventArgs doesn't have one constructor, when it clearly does (clearly to me at least).
I've only included the bit of code that I think applies. It seems like such a simple thing that I am at a loss.
public partial class MainWindow : Window
{
Coffee coffeeOnHand;
SweetTea sweetTeaOnHand;
BlueberryMuffin blueberryMuffinOnHand;
public MainWindow()
{
InitializeComponent();
//The following reads the inventory from file, and assigns each inventory item to the Coffee, SweatTea
//and BlueberryMuffin objects in memory.
using (Stream input = File.OpenRead("inventory.dat"))
{
BinaryFormatter formatter = new BinaryFormatter();
coffeeOnHand = (Coffee)formatter.Deserialize(input);
sweetTeaOnHand = (SweetTea)formatter.Deserialize(input);
blueberryMuffinOnHand = (BlueberryMuffin)formatter.Deserialize(input);
}
//The following adds whatever information is loaded from the objects on file from above
//into the dropdown box in the menu.
SelectedItemDropdown.Items.Add(coffeeOnHand);
SelectedItemDropdown.Items.Add(sweetTeaOnHand);
SelectedItemDropdown.Items.Add(blueberryMuffinOnHand);
}
public class ScanInfoEventArgs : EventArgs
{
ScanInfoEventArgs(string scanType)
{
this.scanType = scanType;
}
public readonly string scanType;
}
public class Scan
{
//Delegate that subscribers must implement
public delegate void ScanHandler (object scan, ScanInfoEventArgs scanInfo);
//The event that will be published
public event ScanHandler onScan;
public void Run()
{
//The ScanInfoEventArgs object that will be passed to the subscriber.
ScanInfoEventArgs scanInformation = new ScanInfoEventArgs("scanType");
// Check to see if anyone is subscribed to this event.
if (onScan != null)
{
onScan(this, scanInformation);
}
}
}
You need to make your constructor public. All class members default to private, which means the outside world can't get at them.
Since the compiler didn't see a matching public constructor (as in, one the code could actually invoke), it threw the error you saw.
Correct code:
public ScanInfoEventArgs(string scanType)
{
this.scanType = scanType;
}
Note that internal would work as well if all code resides in the same assembly.
I have a big problem with MVVM design. I am trying to catch every PropertyChanged of my inner nested objects, including futhermore propertchanged of their nested objects, inside my ViewModel but I dont know how to do it.
Here is my structure:
class MyVM
{
public MyVM()
{
this.SomeData = new SomeData();
this.SomeData.NestedObj = new MyNestedDat();
this.SomeData.Str = "This tiggers propertychanged inside MyDat class";
// this triggers propertychanged event inside MyNestedDat class
this.SomeData.NestedObj.Num = 123;
}
// and here should be a method where i catch all possibe propertychanges from my nested objets and their nested objets, how do i do that?
public MyDat SomeData
{
get;
set;
}
}
class MyDat : INotifyPropertyChanged
{
private string str;
public string Str;
{
get { return this.str;}
set
{
this.str = value;
this.PropertyChanged(this, "Str");
}
}
publicMyNestedDat NestedObj
{
get;
set;
}
}
class MyNestedDat : INotifyPropertyChanged
{
private int num;
public int Num
{
get{ return this.num;}
set
{
this.num = value;
this.PropertyChanged(this, "Num");
}
}
}
How do i get this to work? I am really clueless where to start.
MyNestedDat class throws PropertyChanged, MyDat class throws propertychanged and i want to catch them all inside my viewmodel. How can i do that?
In my opinion there are a few conceptual things wrong with what you are asking. Just imagine you get a solution that works for your scenario (that you are happy with) and consider the following:
What happens if another layer is added? do you still expect it to work the same?
Should property changes be propagated (viewModel1.propA notifies viewModel2.PropA)?
Should property changes be transformed (viewModel1.SomeProp notifies ViewModel2.AnotherProp)?
Is performance a concern? how will this perform if you need to propagate the property changed events through many levels?
This should be raising alarm bells that the current approach is not the right path to tread.
What you need is a way to provide communication between your viewModels in a loosely coupled way so that you viewModels do not even need to know about each others existence. The beauty of this is that this will also work in other situations not just for property changes.
For your case of property changed events, one viewModel wants to know when something happens (it could be something other than a property changed event, remember). This means the other viewModel needs some way of saying "Hey, a property has changed" (or "My state has changed", "That database call has finished" etc).
Now in C# you can provide events which provide this feature....except, now your objects know about each other which leaves you with the same problem you had before.
To overcome this problem you need another object, a mediator (lets call it Messenger in this example), whose sole purpose is to handle the message passing between the objects so that they can live in ignorance of each other.
The general idea is this. In the viewModel that provides notifications you might do something like this:
public string MyProp
{
get { return _myProp; }
set
{
_mProp = value;
OnPropertyChanged("MyProp");
Messenger.PostMessage(new VMChangedMessage { ViewModel = this, PropertyName = "MyProp" });
}
}
And in the viewModel that is interested in the event you might do something like this:
public class ViewModel2
{
public ViewModel2()
{
Messenger.Subscribe<VMChangedMessage>(handleMessage);
}
private void handleMessage(VMChangedMessage msg)
{
// Do something with the information here...
}
}
Notice that the two viewModels never reference each other. They are now loosely-coupled.
There are a number of pre-existing implementations already available and it isn't difficult to create your own (the messenger basically keeps a list of objects that are interested in a certain message and iterates the list when it needs to notify the interested parties). There are a few things that can be implemented differently (some implementations just pass string messages around rather than encapsulating the information in objects, and some handle the clean-up of observers automatically).
I would recommend using Josh Smiths (excellent) MVVM Foundation which includes a messenger class. It's also open source so you can see how it works.
There is no clear constraint about what PropertyName should contains in PropertyChangedEventArgs.
See Subscribe to INotifyPropertyChanged for nested (child) objects.
Here is an example :
class A : BaseObjectImplementingINotifyPropertyChanged {
private string m_name;
public string Name {
get { return m_name; }
set {
if(m_name != value) {
m_name = value;
RaisePropertyChanged("Name");
}
}
}
}
class B : BaseObjectImplementingINotifyPropertyChanged {
private A m_a;
public A A {
get { return m_a; }
set {
if(m_a != value) {
if(m_a != null) m_a.PropertyChanged -= OnAPropertyChanged;
m_a = value;
if(m_a != null) m_a.PropertyChanged += OnAPropertyChanged;
RaisePropertyChanged("A");
}
}
}
private void OnAPropertyChanged(object sender, PropertyChangedEventArgs e) {
RaisePropertyChanged("A." + e.PropertyName);
}
}
B b = new B();
b.PropertyChanged += (s, e) => { Console.WriteLine(e.PropertyName); };
b.A.Name = "Blah"; // Will print "A.Name"
The best thing to do here is to separate the idea of a Model and a ViewModel.
By having a ViewModel object that is flatter than the Model you can avoid this scenario. Using an automatic mapping tool like Automapper then allows you to map the Model to the ViewModel and vice versa.
https://github.com/AutoMapper/AutoMapper/wiki/Flattening
class MyDatViewModel : INotifyPropertyChanged
{
public string Str
{
// ... Get Set
}
public int NestedObjNum
{
// ... Get set
}
}
// Configure AutoMapper
Mapper.CreateMap<MyDat, MyDatViewModel>();
// Perform mapping
MyDatViewModel viewModel = Mapper.Map<MyDat, MyDatViewModel>(someData);
In Dustin Campbell's answer in question Return a value from a Event — is there a Good Practice for this? it is stated that instead of returning data from an event handler, we can have a writable property on a set of custom EventArgs that is passed to the event similar to Cancel property of the WinForms FormClosing event.
How do I provide feedback to event caller using properties in EventArgs?
My specific scenario is that there is a Controller class that does Job A and there are many classes requesting the Job A to be done. Thus, the controller is subscribed to this event on all classes.
I want to give some feedback to the caller that the job is done. The tricky part is that those classes are module-like and controller doesn't know anything about them.
My though is to include that writable property to the delegate of the event in order for the controller to give feedback through it. This property could somehow be invoked using reflection, which is fine in my scenario.
you cannot define properties for delegates.
Also you do not need reflection for such a mechanism.
What you want to do is to define your "return"-properties in the EventArgs-derived class.
A simple such class would be:
public class JobEventArgs : EventArgs {
public bool Done { get; set; }
}
Now you can declare your event in the class as
public event EventHandler<JobEventArgs> Job;
Usage in the method which handles the event:
public void DoJob(object s, JobEventArgs args) {
// do stuff
args.Done = true;
}
and in the event invoking code:
public void FireJobEvent() {
var args = new JobEventArgs();
this.Job(this, args);
if(!args.Done) {
// the job was not handled
}
}
But frankly it rather seems like you want to do a job asynchronously with a notification when it finishes.
Which would result in syntax like..
class Module {
public void JobCompleted(IAsyncResult r) {
if(!r.IsCompleted)
return;
Console.WriteLine("The job has finished.");
}
public void ExecuteJob() {
var job = new EventArgs<JobEventArgs>((s, a) => { this.controller.JobA(); });
job.BeginInvoke(null, null,
r =>
{
this.JobCompleted(r);
if(r.IsCompleted)
job.EndInvoke(r);
}, null);
}
}
Here is the code for custom event args. I am confuse about use of those and also role of those. I can not understand this property public object AddedObject { get; private set; } the code is here :
public class ObjectAddedEventArgs : EventArgs
{
public ObjectAddedEventArgs(object addedObject)
{
AddedObject = addedObject;
}
public object AddedObject { get; private set; }
}
I can not understand use of the get and set property of added object. Please explain to me.
The AddedObject property is what is called an "auto property", which simply means that the C# compiler will generate a private variable to hold the value of the property. The "get" is the mechanism which allows you to read the value of the property. The "set" is the mechanism which allows you to set the value of the property, although in this case since the set is private you aren't able to set the value. This translates to code which would look roughly like this:
private object _AddedObject;
public object AddedObject
{
get { return this._AddedObject; }
private set { this._AddedObject = value; }
}
The class itself (the ObjectAddedEventArgs class) is used to provide additional data (the AddedObject value) to an event handler which, presumably, would access that data and do something with it as part of it's response to the event.
As per Microsoft's documentation:
EventArgs is the base class for classes containing event data.
....
This class contains no event data; it is used by events that do not
pass state information to an event handler when an event is raised. If
the event handler requires state information, the application must
derive a class from this class to hold the data.
That being said, the original developer of that class intended to handle events and at the same time making the object AddedObject available to the event handler method. See the website above for a nice example.
the good thing when you declare your events like this
event EventHandler<ObjectAddedEventArgs> MyObjectAddedEvent;
you can subscribe to it in a weak manner easily
myObjectInstance.MyObjectAddedEvent += new EventHandler<ObjectAddedEventArgs>(MyObjectAddedEventMethod).MakeWeak(eh => d.MyObjectAddedEvent -= eh);
private void MyObjectAddedEventMethod(object sender, ObjectAddedEventArgseventargs)
{
//do something with the event args
}
the weak stuff you find here.
He everybody,
I'm trying to setup a project management class.
In order to see if somthing in the data changed i want to implement events on the lower level of the programming structure. I have some Classes extending the ProjectComponent Class. The base class has an event and event throwing methode, which the childcomponents can use.
Now I have a couple of custom list (nameley eList) in the project object.
Because all the child component have a common parent, ProjectComponent, i would like my custom list object (eList) to subscribe to the event when an object is added and unsubscribe when removed.
However when trying to prog this, i received the following error:
'ProjectComponent' does not contain a
definition for 'itemChanged' and no
extension method 'itemChanged'
accepting a first argument of type
'ProjectComponent'
Which is kind of wierd seeing as the class clearly has that public field.
Here is a the code:
public class ProjectComponent
{
public event ItemChanged itemChanged;
public void throwItemChangedEvent(ItemChangedEventArgs Arguments)
{
if (itemChanged != null)
itemChanged(new Object(), Arguments);
}
}
public class eList<ProjectComponent> : IList<ProjectComponent>
{
List<ProjectComponent> internalList = new List<ProjectComponent>();
public override void Add(ProjectComponent Item)
{
this.internalList.Add(Item);
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
}
private void ItemChanged_Handler(object sender, ItemChangedEventArgs eventArgs)
{
//do stuff here
}
}
An example how it would be called is:
public eList<ChildClass> Children = new eList<ChildClass>();
The idea is that when an object in the list is edited the list object recieve an object like so:
Children.childstring = "anything";
At the moment the field inside the Children object is changed an event could be recieved.
My question is simply what am i doing wrong, why cant i suscribe to the ProjectComponent event inside the eList class?
Or does anyone know a better way to achive the same results?
Thanks in Advance,
Harry
Edit: Definition of ItemChanged delagate:
public delegate void ItemChanged(object sender, ItemChangedEventArgs eventArgs);
public class ItemChangedEventArgs : EventArgs
{
private String p_CallStack;
public String CallStack
{
get { return this.p_CallStack; }
set { this.p_CallStack = value; }
}
public ItemChangedEventArgs()
{
p_CallStack = "";
}
public ItemChangedEventArgs(String StackStart)
{
p_CallStack = StackStart;
}
}
you have 2 errors:
1.
in generic class definition you must use variables not existing classes:
public class eList<ProjectComponent>: ...
--> public class eList<T>: ...
in your case you want to do:
public class eList : IList<ProjectComponent>
2.
Item.itemChanged += new Item.itemChanged(ItemChanged_Handler);
new Item.itemChanged has no meaning, you have to use the underlying delegate type of your event:
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
N.B:
your code does not respect at all design guidelines for c#
More informations here:Naming Guidelines
Shouldn't it be
Item.itemChanged += new ItemChanged(ItemChanged_Handler);