I can't figure out how to use the CanExecuteChangedEventManager in MyCommand : ICommand.
I tried the following but value is the wrong type:
public event EventHandler CanExecuteChanged
{
add
{
CanExecuteChangedEventManager.AddHandler(this, value);
}
remove
{
CanExecuteChangedEventManager.RemoveHandler(this, value);
}
}
The class I'm writing will look like this but without leaks if possible:
public class ManualRelayCommand : ICommand
{
// CanExecute() and Execute() excluded
public event EventHandler CanExecuteChanged;
public virtual void RaiseCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null)
{
Application.Current.Dispatcher.InvokeAsync(() => handler(this, EventArgs.Empty));
}
}
}
CanExecuteChangedEventManager is a class supporting weak event pattern. It is very common for controls developer to use weak events since you wish the controls not to have strong references to data.
CanExecuteChangedEventManager is used like this.
public event EventHandler<EventArgs> CanExecuteChanged
{
add
{
CanExecuteChangedEventManager.AddHandler(this, value);
}
remove
{
CanExecuteChangedEventManager.RemoveHandler(this, value);
}
}
You need EventHandler<EventArgs> and that would be it.
If you still have questions about this feel free to ask :)
Edit:
You are not creating a control you are just creating a RelayCommand which inherits from ICommand.
You do not need CanExecuteChangedEventManager.
When you inherit from ICommand you must implement public event EventHandler CanExecuteChanged;
You can let it be that way without changing it. You dont change PropertyChanged event either do you? Just let it be there and it will work magically.
Controls who allow commanding know how to subscribe to that event. Just like PropertyChanged event from INotifyPropertyChanged interface. :)
Implemented it like this:
public class ManualRelayCommand
{
///...
public override event EventHandler CanExecuteChanged
{
add
{
InternalCanExecuteChangedEventManager.AddHandler(this, value);
}
remove
{
InternalCanExecuteChangedEventManager.RemoveHandler(this, value);
}
}
private event EventHandler InternalCanExecuteChanged;
public void RaiseCanExecuteChanged()
{
EventHandler handler = InternalCanExecuteChanged;
if (handler != null)
{
if (_raiseCanExecuteOnDispatcher)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() => handler(this, new EventArgs())));
}
else
{
handler(this, new EventArgs());
}
}
}
private class InternalCanExecuteChangedEventManager : WeakEventManager
{
private static readonly InternalCanExecuteChangedEventManager Manager = new InternalCanExecuteChangedEventManager();
static InternalCanExecuteChangedEventManager()
{
SetCurrentManager(typeof(InternalCanExecuteChangedEventManager), Manager);
}
internal static void AddHandler(ManualRelayCommand source, EventHandler handler)
{
Manager.ProtectedAddHandler(source, handler);
}
internal static void RemoveHandler(ManualRelayCommand source, EventHandler handler)
{
Manager.ProtectedRemoveHandler(source, handler);
}
////protected override ListenerList NewListenerList()
////{
//// return new ListenerList();
////}
protected override void StartListening(object source)
{
((ManualRelayCommand)source).InternalCanExecuteChanged += DeliverEvent;
}
protected override void StopListening(object source)
{
((ManualRelayCommand)source).InternalCanExecuteChanged -= DeliverEvent;
}
}
}
Related
I have the following code with 3 different classes. I am trying to
Subscribe event from class B to method (event handler) defined in
class ControlSystem. All compiles fine, it works no problem but the event handler method is never triggered... What am I doing wrong?
namespace EventTest
{
public class ControlSystem : CrestronControlSystem
{
A myObject = new A();
public ControlSystem(): base()
{
Thread.MaxNumberOfUserThreads = 100;
// Subscribe Event
myObject.mySubObject.BEvent += HandleBEvent;
// Throw Event
myObject.mySubObject.ThrowEvent();
}
public override void InitializeSystem()
{
}
public void HandleBEvent(object sender, EventArgs args)
{
Console.WriteLine("Something happend to {0}", sender);
}
}
public class A
{
public B mySubObject;
public A()
{
mySubObject = new B();
}
}
public class B
{
public EventHandler BEvent;
public B(){}
public void ThrowEvent()
{
EventHandler handler = BEvent;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
}
Real code links below (it works with Embeded system so you won't be able to compile it). Idea is to have button press to trigger an event which could
alarm other UIs that something happend to it.
http://ideone.com/NJz2Ek
Thanks
You are missing the event keyword.
public event EventHandler BEvent;
is what needs to be there.
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.
public class Basket
{
private int _unitCount;
public int UnitCount
{
get { return _unitCount; }
set
{
_unitCount = Math.Max(0, value);
OnUnitCountChanged(new EventArgs());
}
}
public event EventHandler UnitCountChanged;
public event EventHandler Depleted;
protected virtual void OnUnitCountChanged(EventArgs args)
{
var handler = UnitCountChanged;
if(handler!=null) { handler(this, args); }
if(_unitCount == 0) { OnDepleted(new EventArgs()); }
}
protected virtual void OnDepleted(EventArgs args)
{
var handler = UnitCountChanged;
if(handler!=null) { handler(this, args); }
}
}
Is there a problem with checking the conditions for Depleted and raising that event if necessary within the UnitCountChanged event, or should I be doing both in the UnitCount setter (and anywhere else in a non-trivial example)?
While I have seen it, I would recommend against it and raise the event in methods that it would occur in, like your UnitCount setter. Since you have the virtual access modifier keyword, someone could override the method and if they don't call the base object it wouldn't work as expected.
I'm not a fan of making it more complicated to use my code.
There are times when it may be useful (for example, if you are extending a base class and do not have the ability to override the methods that are raising the events), but in general, I'd recommend against it.
In this case, I'd say it's better to raise both events in the UnitCount setter:
public int UnitCount
{
get { return _unitCount; }
set
{
_unitCount = value;
OnUnitCountChanged(new EventArgs());
if(_unitCount == 0) { OnDepleted(new EventArgs()); }
}
}
I have a custom control in C# WinForms called BaseControl and there I have a property called Selected.
I want to have an event SelectedChanged and virtual method OnSelecteChanged in the base control and they should behave in the same manner as we have in Control class for many properties i.e. Click event and OnClick method.
Means anyone who derives from my BaseControl can either bind to the event or can override the OnSelectedChanged method.
So, when the value of Selected property is changed event should be fired and if the method is overridden control should go to that method.
I know how to fire the event but don't know how to do it for method.
Please guide me...
Below is an example of how events should be implemented:
public class BaseControl : Control
{
private object _selected;
public object Selected
{
get { return _selected; }
set
{
if (!Equals(_selected, value))
{
_selected = value;
OnSelectedChanged(EventArgs.Empty);
}
}
}
public event EventHandler SelectedChanged;
protected virtual void OnSelectedChanged(EventArgs e)
{
if (SelectedChanged != null)
SelectedChanged(this, e);
}
}
With this example, you can override OnSelectedChanged in an overriden class, like this:
public class MyControl : BaseControl
{
protected override void OnSelectedChanged(EventArgs e)
{
base.OnSelectedChanged(e);
// My own logic.
}
}
private bool _selected;
public bool Selected
{
get { return _selected; }
set
{
if (value != _selected)
{
_selected = value;
OnSelectedChanged();
}
}
}
public event EventHandler SelectedChanged;
protected virtual void OnSelectedChanged()
{
var handler = SelectedChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
Basically you don't fire the event from your Selected property setter - you call the method, and make the method call the event. Anyone overriding the method should call base.OnSelectedChanged to make sure the event still fires. So your method should look something like this:
protected virtual void OnSelectedChanged(EventArgs e) {
EventHandler handler = Selected; // Or your own delegate variable
if (handler != null) {
handler(this, e);
}
}
I apologize for the newbie question, but I am struggling with this problem. I have the following TextBlock defined:
<TextBlock Text="{Binding Source={x:Static local:DeviceManager.Instance},
Path=Player.CurrentArtist}"></TextBlock>
The DeviceManager is a singleton that functions as a facade for other classes. For example, Player is a property of type IPlayer which represents an music-playing application. I would like the TextBlock to display the artist that is currently playing, which is periodically updated in the Player.CurrentArtist property.
Unfortunately, I cannot get the TextBlock to update when the CurrentArtist property updates. Both the DeviceManager and the IPlayer implement INotifyPropertyChanged, but when I step through the application, the DeviceManager does not have an event handler attached to it.
Does anyone have a suggestion for how to update the text block while preserving the singleton-facade?
Here is the code for the INotifyPropertyChanged members in both the DeviceManager and the IPlayer subclass:
public sealed class DeviceManager : INotifyPropertyChanged
{
// Singleton members omitted
public IPlayer Player
{
get { return player; }
set
{
this.player = value;
player.PropertyChanged += new PropertyChangedEventHandler(device_PropertyChanged);
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void device_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(sender, e);
}
}
#endregion
}
class MediaPlayer : IPlayer
{
private string artist;
private string title;
public event PropertyChangedEventHandler PropertyChanged;
public void Play(string artist, string title)
{
this.artist = artist;
this.title = title;
OnPropertyChanged("Player:Song");
}
private void OnPropertyChanged(string p)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(p));
}
}
public string CurrentTitle
{
get { return title; }
}
public string CurrentArtist
{
get { return artist; }
}
}
The problem is that WPF is never notified of the value of the CurrentArtist property changing. You can either implement a private setter for the CurrentArtist property, which will trigger the PropertyChanged event, or trigger a PropertyChanged event for the CurrentArtist property in MediaPlayer.Play().
WPF only responds to PropertyChanged if the name you pass in (i.e. right now "Player:Song") is the same as the property you're bound to - change the PropertyChanged to "CurrentArtist" and you'll see it update properly.
You are not raising the PropertyChanged event, what you need is:
public sealed class DeviceManager : INotifyPropertyChanged
{
// Singleton members omitted
public IPlayer Player
{
get { return player; }
set
{
this.player = value;
OnPropertyChanged(this, new PropertyChangedEventArgs("Player"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(sender, e);
}
}
#endregion
}
How does the UI know when you change the Player property? From that code it does not look like it raises PropertyChanged to me. Can you post a complete working sample of the problem? Otherwise we're forced to just guess.