Does inheritance matter with events and delegates? - wpf

I've been reading up on delegates, event and WPF for some days now and I am starting to get some understanding of it but there are a few things that is unclear to me.
In this question they explained on how to raise an event on a property is changed.
From what I've understood when it comes to event is that you want to do something when they happend, and that you need to add an function to an event like so
Someclass.PropertyChanged += new PropertyEventHandler(somefunction)
public void somefunction(object sender, EventArgs e){ //Do some code}
But almost in every example, when they use INotifyPropertyChanged that is never used, but they somehow manage to activate the event PropertyChanged.
I can't really make sense of it.
Do you need to add function to a new eventhandler if you implement an interface with an already declared event?

No need to give it a handler. You implement PropertyChanged so some other code can handle the event. That other code might be yours, but in the case of INotifyPropertyChanged, it's usually the bindings in your views that'll subscribe to your PropertyChanged events.
You can declare an event without adding your own handler to it. You really ought to raise the event once you bothered declaring it, but you don't have to handle it. By raising it, I mean like this:
protected void OnPropertyChanged(String propName)
{
var handler = PropertyChanged;
// If nobody gave it a handler, it'll be null, so check for that.
if (handler != null)
{
// This is what we refer to when we say "raise the event": handler has
// references to at least one handler (because it's not null), and possibly
// dozens. This one "method call" here will magically call all of them.
handler(this, new PropertyChangedEventArgs(propName));
}
}
public String Name {
get { return _name; }
set {
if (_name != value) {
_name = value;
// Call this method to raise PropertyChanged
OnPropertyChanged("Name");
}
}
}
private String _name;
Declaring an event is just saying "In case anybody cares about this thing happening, here's an event that I'll raise when it happens."
Maybe you want to handle that event in some other part of your own code. In WPF, you implement INotifyPropertyChanged so when the user interface has bindings to the properties of an instance of your class, it'll get the notifications it needs.

Related

WPF Is there a simple way to update GUI from main thread [duplicate]

I'm a web and backend programmer by nature. Normally I try to avaoid making windows programs. Now I have to make a WPF client.
I have a background task that raises an event every often time. (It is working like a poller and when the criteria are met an event is raised). Noob as I am I wrote this code that was attached to the event to update the UI.
private void IsDisconnectedEvent()
{
UserWindow.Visibility = Visibility.Hidden;
DisconnectWindow.Visibility = Visibility.Visible;
}
This gives an exception because I am not on the same thread. After some googling I found that I should change the code with:
private void IsDisconnectedEvent()
{
Dispatcher.Invoke(() =>
{
UserWindow.Visibility = Visibility.Hidden;
DisconnectWindow.Visibility = Visibility.Visible;
});
}
This works, but this is not the only event and thus makes my code horrible ugly. Are there better ways to do this?
Regarding this:
This works, but this is not the only event and thus makes my code
horrible ugly
Yes, your WPF-based code will definitely be extremely horrible unless you understand and embrace The WPF Mentality.
Basically, all interactions between your custom logic (AKA Business logic or Application Logic) and the WPF UI should manifest in the form of Declarative DataBinding as opposed to the traditional imperative approach.
This means that there should be nothing like this:
UserWindow.Visibility = Visibility.Hidden;
anywhere in your code, simply because introducing things like that makes your code dependent on the UI and thus only executable on the UI thread.
Instead, the WPF approach to that would be to declaratively DataBind the Visibility propety of the UI element (IN XAML) to a relevant bool property that you can operate from the outside, like this:
<UserWindow Visibility="{Binding ShowUserWindow, Converter={my:BoolToVisibilityConverter}}">
<!-- ... -->
</UserWindow>
Then, you would need to create a relevant class that contains the properties the UI is expecting to bind to. This is called a ViewModel.
Notice that in order to properly support Two-Way WPF DataBinding, your ViewModels must Implement the INotifyPropertyChanged interface.
When doing so, it is also convenient to have the PropertyChanged event from that interface marshalled to the UI thread, so that you no longer have to worry about setting the ViewModel's properties by using the Dispatcher.
Therefore our first step is to have all our ViewModels inherit from a class like this:
(taken from this answer):
public class PropertyChangedBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
//Raise the PropertyChanged event on the UI Thread, with the relevant propertyName parameter:
Application.Current.Dispatcher.BeginInvoke((Action) (() =>
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}));
}
}
Once we have our Property Change Notification Dispatch to the UI Thread in place, we can proceed to create a relevant ViewModel that suits, in this case, the UserWindow and it's DataBinding expectations:
public class UserViewModel: PropertyChangedBase
{
private bool _showUserWindow;
public bool ShowUserWindow
{
get {return _showUserWindow; }
set
{
_showUserWindow = value;
OnPropertyChanged("ShowUserWindow"); //This is important!!!
}
}
}
Finally, you would need to set the Window's DataContext to an instance of it's corresponding ViewModel. One simple way to do that is in the Window's constructor:
public UserWindow() //Window's Constructor
{
InitializeComponent(); //this is required.
DataContext = new UserViewModel(); //here we set the DataContext
}
As you can see in this example, there is literally no need to manipulate the UI element's properties in procedural code. This is good not only because it resolves the Thread Affinity issues (because now you can set the ShowUserWindow property from any thread), but also because it makes your ViewModels and logic completely decoupled from the UI and thus testable and more scalable.
This same concept applies to EVERYTHING in WPF.
One detail that I need to mention is that I'm making use of a technique of Combining MarkupExtension and IValueConverter in order to reduce the the XAML boilerplate involved in using Converters.
You can read more about that in the link and also the MSDN DataBinding page linked above.
Let me know if you need further details.

is it correct to use OnPropertyChanged event to ask application to do something?

My MVVM application contains two views:
AllStrategiesView
StrategyView
When user click certain strategy in AllStrategiesView StrategyView with this strategy is created. I use such code to notify application that StrategyView should be created:
.............
public void OpenStrategyView()
{
OnPropertyChanged("OpenStrategy");
}
.................
private void OnWorkspacePropertyChanged(object sender, PropertyChangedEventArgs e)
{
const string openStrategyString = "OpenStrategy";
if (e.PropertyName == openStrategyString)
{
AllStrategiesViewModel vm = (sender as AllStrategiesViewModel);
OpenStrategy(vm.SelectedStrategy);
}
}
However another part of the program shows error message because there are no such property "OpenStrategy":
/// <summary>
/// Warns the developer if this object does not have
/// a public property with the specified name. This
/// method does not exist in a Release build.
/// </summary>
[Conditional("DEBUG")]
[DebuggerStepThrough]
public void VerifyPropertyName(string propertyName)
{
// Verify that the property name matches a real,
// public, instance property on this object.
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
string msg = "Invalid property name: " + propertyName;
if (this.ThrowOnInvalidPropertyName)
throw new Exception(msg);
else
Debug.Fail(msg);
}
The question is:
Is it right or wrong to use OnPropertyChanged to notify application that something need to be done? Should I rewrite my code to not to use OnPropertyChanged or should I disable VerifyPropertyName code?
This is bad practice. The PropertyChanged event on INotifyPropertyChanged should be used to notify subscribers that a property on the object instance has changed. This is typically used in WPF to notify the UI that it needs to update itself with the new property value.
In MVVM, you should use some kind of commanding or alternative viewmodel/view communication mechanism to invoke verbs (methods) on your view model from the view. The commanding provided by WPF has limitations, so I would recommend using an MVVM framework and the mechanisms that they provide.
Well it depends on what you want it to do. In your case it looks like you have a property "Workspace" which indicates which VM you should be looking at. This doesn't seem too bad of a usage IMHO.
If you were doing something completely unrelated to the property that was changed then it might work, but it's certainly not what I'd expect it to do (see Principle of Least Astonishment). OnPropertyChanged is intended to indicate that a property that has been bound to has changed and should be re-fetched.
You can of course just have another event on your ViewModel, like:
public event Action<String> OpenStrategy;
One more thing... This code is completely redundant:
const string openStrategyString = "OpenStrategy";
if (e.PropertyName == openStrategyString)
the following is exactly the same, from the compiler's perspective, and much more readable:
if (e.PropertyName == "OpenStrategy")
There's nothing wrong in asking your application to do something in the PropertyChanged event, however do not raise a PropertyChanged event just to ask the application to do something.
PropertyChanged is used to indicate that a property has changed, and should be used for that only.
Devdigital's answer gives a good example, that the UI uses the PropertyChange notification to know when it should update. Other objects can also subscribe to receive change notifications, and they should only be notified when a value changes, not when you want to run some application code.
Using your example, I would rewrite it like this:
public void OpenStrategyView()
{
OpenStrategy(this.SelectedStrategy);
}
private void OnWorkspacePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "SelectedStrategy")
{
OpenStrategyView();
}
}

OnClick event on compound UserControls

I want to create a UserControl with several controls inside. These controls should behave simmilar to the radio buttons, i. e., the status of one of them affects the status of the rest. To do that I would like to be able to handle the OnClick event on each of the controls from the parent.
One solution could be to call a method of the parent, to perform the global UserControl change, from the child controls' OnClick method. Something like:
class Child : UserControl
{
...
protected override void OnClick(EventArgs z_args)
{
// do own stuff
((PartentType)Parent).ChangeStatus(this);
}
...
}
This is a solution, but I wonder if there is a more standard an elegant way to solve this issue. Thanks!
No, this is very bad, a control should never depend on having a specific parent. Do it the same way any Windows Forms control does it: if something interesting happens that a parent might be interested in then raise an event:
public event EventHandler StatusChanged;
public int Status {
get { ... }
}
protected override void OnClick(EventArgs z_args) {
// do own stuff
//...
var handler = StatusChanged;
if (handler != null) handler(this, EventArgs.Empty);
}
Consider putting the event raising code in a private setter for the Status property.

Is Josh Smith's implementation of the RelayCommand flawed?

Consider the reference Josh Smith' article WPF Apps With The Model-View-ViewModel Design Pattern, specifically the example implementation of a RelayCommand (In Figure 3). (No need to read through the entire article for this question.)
In general, I think the implementation is excellent, but I have a question about the delegation of CanExecuteChanged subscriptions to the CommandManager's RequerySuggested event. The documentation for RequerySuggested states:
Since this event is static, it will
only hold onto the handler as a weak
reference. Objects that listen for
this event should keep a strong
reference to their event handler to
avoid it being garbage collected. This
can be accomplished by having a
private field and assigning the
handler as the value before or after
attaching to this event.
Yet the sample implementation of RelayCommand does not maintain any such to the subscribed handler:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
Does this leak the weak reference up to the RelayCommand's client, requiring that the user of the RelayCommand understand the implementation of CanExecuteChanged and maintain a live reference themselves?
If so, does it make sense to, e.g., modify the implementation of RelayCommand to be something like the following to mitigate the potential premature GC of the CanExecuteChanged subscriber:
// This event never actually fires. It's purely lifetime mgm't.
private event EventHandler canExecChangedRef;
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
this.canExecChangedRef += value;
}
remove
{
this.canExecChangedRef -= value;
CommandManager.RequerySuggested -= value;
}
}
I've found the answer in Josh's comment on his "Understanding Routed Commands" article:
[...] you have to use the WeakEvent pattern in your CanExecuteChanged
event. This is because visual elements will hook that event, and since
the command object might never be garbage collected until the app
shuts down, there is a very real potential for a memory leak. [...]
The argument seems to be that CanExecuteChanged implementors must only hold weakly to the registered handlers, since WPF Visuals are to stupid to unhook themselves. This is most easily implemented by delegating to the CommandManager, who already does this. Presumably for the same reason.
I too believe this implementation is flawed, because it definitely leaks the weak reference to the event handler. This is something actually very bad.
I am using the MVVM Light toolkit and the RelayCommand implemented therein and it is implemented just as in the article.
The following code will never invoke OnCanExecuteEditChanged:
private static void OnCommandEditChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var #this = d as MyViewBase;
if (#this == null)
{
return;
}
var oldCommand = e.OldValue as ICommand;
if (oldCommand != null)
{
oldCommand.CanExecuteChanged -= #this.OnCanExecuteEditChanged;
}
var newCommand = e.NewValue as ICommand;
if (newCommand != null)
{
newCommand.CanExecuteChanged += #this.OnCanExecuteEditChanged;
}
}
However, if I change it like this, it will work:
private static EventHandler _eventHandler;
private static void OnCommandEditChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var #this = d as MyViewBase;
if (#this == null)
{
return;
}
if (_eventHandler == null)
_eventHandler = new EventHandler(#this.OnCanExecuteEditChanged);
var oldCommand = e.OldValue as ICommand;
if (oldCommand != null)
{
oldCommand.CanExecuteChanged -= _eventHandler;
}
var newCommand = e.NewValue as ICommand;
if (newCommand != null)
{
newCommand.CanExecuteChanged += _eventHandler;
}
}
The only difference? Just as indicated in the documentation of CommandManager.RequerySuggested I am saving the event handler in a field.
Well, according to Reflector it's implemented the same way in the RoutedCommand class, so I guess it must be OK... unless someone in the WPF team made a mistake ;)
I believe it is flawed.
By rerouting the events to the CommandManager, you do get the following behavior
This ensures that the WPF commanding
infrastructure asks all RelayCommand
objects if they can execute whenever
it asks the built-in commands.
However, what happens when you wish to inform all controls bound to a single command to re-evaluate CanExecute status? In his implementation, you must go to the CommandManager, meaning
Every single command binding in your application is reevaluated
That includes all the ones that don't matter a hill of beans, the ones where evaluating CanExecute has side effects (such as database access or long running tasks), the ones that are waiting to be collected... Its like using a sledgehammer to drive a friggen nail.
You have to seriously consider the ramifications of doing this.
I may be missing the point here but doesn't the following constitute the strong reference to the event handler in the contructor?
_canExecute = canExecute;

how do i get a wpf window to refresh?

I am building a simple roulette app. The player(UI) puts together a list of bets and submits them to the table object to be evaluated and paid out. I've got the code to work and the game process goes smoothly. The problem is that after a turn I can't get the player balance(textblock) or the betlist(listview) to update. Is there some sort of global window refresh command I am missing, or do I have to manually set each of these to update somehow?
WPF can take care of updating these values for you automatically, but you have to let it know when things have changed. Typically, this is done by using DependencyProperties on your model objects, but it can also be done by implementing INotifyPropertyChanged. In either case, when you update a property's value, the PropertyChanged event gets called; WPF automatically subscribes to this event when it binds to a value, and will update the UI when a change occurs. Without this notification, WPF won't check to see if the values in your object have changed, and you won't see the change reflected on the screen.
What about implementing INotifyPropertyChanged, and bind the balance and the betlist to the controls you are using?
Something like:
public class Player : INotifyPropertyChanged
{
private int _balance;
#region Properties
public int Balance
{
get { return this._balance; }
set
{
if (this._balance != value)
{
this._balance = value;
NotifyPropertyChanged("Balance");
}
}
}
public BindingList<Bet> BetList { get; set; }
#endregion // Properties
private void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
public class Bet
{
// some code
}
For the binding list you wouldn't need to implement anything since it implements an interface that notifies changes to whatever is bound to (IRaiseItemChangedEvents). But then again you could be using a different approach.

Resources