Windows Store App (8.1): INotifyPropertyChanged Must Be Top Level? - c#

Why does this:
public class ViewModel : INotifyPropertyChanged
{
private string _bp;
public event PropertyChangedEventHandler PropertyChanged;
public string BindableProperty
{
get { return _bp; }
set
{
_bp = value;
NotifyPropertyChanged();
}
}
protected void NotifyPropertyChanged( [CallerMemberName] string caller = "" )
{
var eventHandler = PropertyChanged;
if( eventHandler != null )
eventHandler( this, new PropertyChangedEventArgs( caller ) );
}
}
bind correctly in a Windows Store app Page (i.e., the binding target is listening to the PropertyChanged event, as can be verified by breaking in NotifyPropertyChanged and seeing that eventHandler is not null). But this:
public interface IViewModel : INotifyPropertyChanged
{
string BindableProperty { get; set; }
}
public class ViewModel : IViewModel
{
private string _bp;
public event PropertyChangedEventHandler PropertyChanged;
public string BindableProperty
{
get { return _bp; }
set
{
_bp = value;
NotifyPropertyChanged();
}
}
protected void NotifyPropertyChanged( [CallerMemberName] string caller = "" )
{
var eventHandler = PropertyChanged;
if( eventHandler != null )
eventHandler( this, new PropertyChangedEventArgs( caller ) );
}
}
fails to bind (i.e., eventHandler is always null, and the binding target never reflects updates to BindableProperty).
I read someplace that since WinRT isn't managed code it doesn't support reflection. So instead some component of the OS builds a hidden object, when a managed app starts, storing type information which would otherwise be obtained through reflection. The behavior I'm noticing looks like whatever type scanning process is used isn't smart enough to trace back through a chain of derived interface definitions.
So is my theory correct? Or am I missing something else which is causing the problem?
Edit
Thanks, Rob, for replying. To provide a bit more context, I am updating the properties within an asynchronous method called from within a couple of asynchronous event handlers (e.g., private async void navigationHelper_LoadState( object sender, LoadStateEventArgs e ), private async void btnSeek_Click( object sender, RoutedEventArgs e ).
More importantly, when I went back and re-ran the what I thought was the same code this morning everything worked as expected, even with the "dervied" interface definition. So obviously I changed something along the way that I don't remember.
Given my recent experience I now suspect I'm having a problem with the way I'm writing and calling various asynchronous methods. It's a new area to me, and I've noticed all sorts of run-time difficulties if, for example, one forgets to "await" an asynchronous operation. The app will still compile, but the run-time behavior is very different.

Related

Don't Understand How INotifyPropertyChanged function

INotifyPropertyChanged interface implementation (appropriate event) and helper method works fine in my code but I really don't understand how it works. My book does a poor job of explaining it to me in my opinion or I am not very smart.
We have a separate class Car.cs added to my solution with the following code (example from the book) and it should work in TwoWay Binding regards to TextBox control in my WPF application being changed when object's instance is being changed too:
public class Car: INotifyPropertyChanged
{
private string _make;
private string _model;
public event PropertyChangedEventHandler PropertyChanged;
public Car()
{
}
public string Make
{
get { return _make; }
set
{
if (_make != value)
{
_make = value;
OnPropertyChanged("Make");
}
}
}
public string Model
{
get { return _model; }
set
{
if(_model != value)
{
_model = value;
OnPropertyChanged("Model");
}
}
}
private void OnPropertyChanged (string propertyName)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}}
And here is the code which I made myself after learning Microsoft learning materials and it looks and works better imo:
public class Car: INotifyPropertyChanged
{
private string _make;
private string _model;
public event PropertyChangedEventHandler PropertyChanged;
public Car()
{
}
public string Make
{
get { return _make; }
set
{
_make = value;
OnPropertyChanged();
}
}
public string Model
{
get { return _model; }
set
{
_model = value;
OnPropertyChanged();
}
}
private void OnPropertyChanged ()
{
if (PropertyChanged != null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(""));
}
} }
So I have the foolowing question regards to example from the book (the first one):
What this part means? What's the point to check if property not equals to value (never saw anything like it before when during the Set part of the property you check that field of the class checked for being not equalled to value)? Code works even without it. No explanation for it in the book. Here is the code under question:
set
{
if (_make != value)
{
_make = value;
OnPropertyChanged("Make");
}
Why if you'll write the name of the property without brackets in the above-mentioned small piece of code (in subparagraph one) then it will not work? I meant if you'll write Make then it does not work and you should write "Make".
Thanks in advance!
Here is a basic example of how to correctly implement the IPropertyChanged interface, which notifies the view to re-draw on property changing its value.
public class PropertyChangedEventStackOverflow : INotifyPropertyChanged
{
//We have a private property of the same public property. This allows us to store the privous value of the property which we can
//get at any time when we ask.
string name = string.Empty;
//Public property is required to do two-way-binding or one-way-binding from model to the view.
public string Name
{
get => name;
set
{
if (name == value) //Check if the private property is already equals to the exact same value to avoid extra memory
return; //and uneccasary screen re-drawing. So we just return and avoid calling the OnPropertyChanged.
name = value; //If the value is different meaning we want to notify view and tell it to re-draw the screen for us.
OnPropertyChanged(nameof(Name));
}
}
//We create this helper metod to avoid doing something like this every single time we want to notify
string surname = string.Empty;
public string Surname
{
get => surname;
set
{
if (surname == value)
return;
surname = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Surname)));
}
}
//Here is the method to create for OnPropertyChangedEvent
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
If you want to go step further and want to have an Action when your property has changed you can do something like this. backingStore type T = private property
public bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
You can give it an action to execute if once a property has changed.
Because raising the PropertyChanged event can be expensive in terms of performance (for example when a complex view has to redraw itself in order to display the latest data), it's a recommended pattern to raise it only when necessary.
It's only necessary when the new value has changed. To update the binding when the new value and the old value are the same is redundant and potentially expensive.
The following example is a very verbose version to highlight what's going on:
private string myProperty;
public string MyProperty
{
get => this.myProperty;
set
{
string newValue = value;
string oldValue = this.MyProperty;
if (newValue != oldValue)
{
this.myProperty = newValue;
OnPropertyChanged(nameof(this.MyProperty));
}
}
}
For reasons of performance, passing an empty string (string.Empty or "") or null to the PropertyChangedEventArgs instance, instead of the property name, will instruct the binding engine to update all bindings of the class that raises the PropertyChanged event.
In other words, it's like raising the PropertyChanged event for all properties at once.
That's why you only do this when this behavior is explicitly desired (for example when you reset and clear all properties):
/* Will raise the PropertyChanged event for ALL properties defined by the declaring type */
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(""));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
/* Will raise the PropertyChanged event ONLY for the particular property that matches the provided property name */
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MyProperty"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.MyProperty)));
"Make" is called a string literal. Every literal enclosed in double-quotes is interpreted as plain text by the compiler (string literal). If it wasn't the double-quotes, the compiler expects the value to be a language object (for example a variable or type).
If you check the signature of the constructor of PropertyChangedEventArgs you will see that it expects the property name as string.
Using Make (without the double-quotes) is a simple value reference (local or member variable) that returns the value of the Make property and not the name of the property (member name).
The property name is required to tell the binding engine which property has changed and therefore which Binding needs to be updated.
The following example assumes that the property Make is set to a value of "BMW":
public string Make
{
get => this.make;
set
{
// For example 'value' is "BMW"
this.make = value;
// Invocation a)
// Pass the property name as argument.
OnPropertyChanged("Make"); // Same as: OnPropertyChanged(nameof(this.Make))
// Invocation b)
// Pass the property value as argument
OnPropertyChanged(Make);
// Verbose version of b)
string modelMake = Make;
OnPropertyChanged(modelMake);
}
}
Version b) won't work, because the binding engine needs the property's member name and not the property value.
See Microsoft Docs: Strings and string literals to learn about strings.
See INotifyPropertyChanged to learn the recommended pattern to implement the interface
Remarks
Checking variable (for example an event delegate) for null using an if statement and the Null-conditional operator ?. or ?[] is redundant.
In high performance code you would want to avoid the redundant double checking.
The following versions are the same:
private void OnPropertyChanged()
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
private void OnPropertyChanged()
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
What's the point to check if property not equals to value
it is just to avoid unnecessary updates. It is not strictly required. Whenever you have events to signal that something is updated it is often a good idea to check if the thing actually changed, since you do not know what is listening to the event, it could potentially trigger some slow computations.
Why if you'll write the name of the property without brackets in the above-mentioned small piece of code (in subparagraph one) then it will not work?
Because the event needs a string. You can let the compiler insert this string for you by writing OnPropertyChanged(nameof(Make)); You can also use CallerMemberName attribute to let the compiler insert this automatically, just call OnPropertyChanged() within your property.
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Going one step further you you can create a method that does both the comparison, field update, and event, letting you write a one line setter => Set(ref _make, value);
private void Set<T>(ref T field, T value, [CallerMemberName] string caller = "")
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(caller);
}
}
However, my preference tend to be to wrap all of this inside a separate class:
public class Changeable<T> : INotifyPropertyChanged
{
private T currentValue;
public Changeable(T initialValue) => currentValue = initialValue;
public T Value
{
get => currentValue;
set
{
if (!EqualityComparer<T>.Default.Equals(currentValue, value))
{
this.currentValue = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
That way you can declare a property like public Changeable<string> Make {get;} = new (""); and bind to it like {Binding Make.Value}
INotifyPropertyChanged is an interface which only requires a class to implement it's requirements. Which is basically "just" an Event.
public interface INotifyPropertyChanged
{
//
// Summary:
// Occurs when a property value changes.
event PropertyChangedEventHandler? PropertyChanged;
}
The Method OnPropertyChanged is just a "helper" to raise this event. But the important part here, is that the INotifyPropertyChanged implementation by itself is not doing anything.
However WinForms and WPF are automatically subscribing in some higher-hirachy classes to such Event. They identify such classes through reflection and add themself to one of the subscribers to the PropertyChanged Event - which your class still needs to raise.
For this purpose you need to override the Setters of your properties:
public string Examle
{
get { return _field; }
set
{
_field = value;
OnPropertyChanged(); // <---
}
}
Otherwise the subscriber will never be notified. However the whole purpose of this is to decouple the handling of changes from the "Model" so your class which act's as container to the data - since the container can be passed to different forms, which might want to handle this container different.
The check if the value actually changed is only something you CAN do - to prevent the notification of the subscriber (let's say your data grid) to re-run all validations you've setup for such property. To avoid unnecessary runs of such validations this if will prevent notifying subscribers of such changes where a value get's re-assigned, but it remains the same.
The auto-wiring of the subscriber however is abstraced for you as developer, which can create difficulties for beginners to understand - however makes your life much more easier on the long run, as you can rely on the Framework as such (less for you to implement, test, etc.) so it's just a "convention" to use INotifyPropertyChange Interface, but the basic building blocks are general C# constructs.
Hope this helped a little :)

How do I correctly implement INotifyPropertyChanged for my bool property and bind to CheckBox.IsChecked?

Novice here. I've been trying to wrap my head around databinding, and wanted to do try out two-way binding of a checkbox in the view to a boolean in a separate class that I've called "State". The point is to ensure that they are always in sync.
So I've made a checkbox in the view and bound it to the aforementioned boolean property in the State-class, accompanied by a button that bypasses the checkbox and toggles the boolean property directly (aptly labeled 'Ninja!'). The point was to test that the checkbox' databinding reacts when the property changes. However, I can't for the best of me figure out how the OnPropertyChanged-method is supposed to be invoked when the property changes.
Here's what I have so far:
<CheckBox x:Name="checkBox" Content="CheckBox" HorizontalAlignment="Left" Margin="232,109,0,0" VerticalAlignment="Top" IsChecked="{Binding Checked, Mode=TwoWay}"/>
<Button x:Name="button" Content="Ninja!" HorizontalAlignment="Left" Margin="228,182,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
And the code for the "State"-class I've made:
namespace TestTwoWayBinding
{
class State : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _checked;
public bool Checked {
get
{
return _checked;
}
set
{
_checked = value;
OnPropertyChanged(Checked);
}
}
public void Toggle()
{
if (!Checked)
{
Checked = true;
}
else
{
Checked = false;
}
}
public State(bool c)
{
this.Checked = c;
}
protected virtual void OnPropertyChanged(string propertyName)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(Checked));
}
}
}
}
And the code-behind on the view for initialization and handling the events:
namespace TestTwoWayBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private State _state;
public MainWindow()
{
InitializeComponent();
_state = new State((bool)checkBox.IsChecked);
}
private void button_Click(object sender, RoutedEventArgs e)
{
_state.Toggle();
}
}
}
From what I gather, OnPropertyChanged expects a String propertyName, but I don't know what that would entail here. When I put in the name of the property (Checked), then that naturally refers to a boolean, not a string. What am I not getting? And what else am I doing wrong, as the checkbox doesn't register the property change when I change it through the button?
The two answers which suggest you pass the string literal "Checked" will work, but IMHO aren't the best way to do it. Instead, I prefer using [CallerMemberName] when implementing the OnPropertyChanged() method. (I have no idea what that third answer is all about…it doesn't appear to have anything to do with this question, and I'd guess it was just copy/pasted from somewhere else).
Here's an example of how I'd write your State class:
class State : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _checked;
public bool Checked
{
get { return _checked; }
set { _checked = value; OnPropertyChanged(); }
}
public void Toggle()
{
Checked = !Checked;
}
public State(bool c)
{
this.Checked = c;
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The key here is that the parameter marked with [CallerMemberName] will automatically be filled in with the correct value from the caller, simply by not passing any value. The default value of null is there just so the compiler will allow the caller to not pass a value.
Note that I also simplified the Toggle() method. There's no need to use an if statement to transform one bool value into another; that's what the Boolean operators are there for.
I also changed the OnPropertyChanged() method so that it's thread-safe, i.e. won't crash if some code unsubscribes the last handler from the PropertyChanged event between the time the event field is compared to null and the time the event is actually raised. Typically, this is a non-issue as these properties are nearly always accessed only from a single thread, but it's easy enough to protect against and is a good habit to get into.
Note that in C# 6, you have the option of just writing PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); for the method body. Not everyone is using the new compiler 100% of the time yet, so I just mention that as an optional choice for you.
Naturally, you also need to set the DataContext correctly, as shown in one of the other answers:
public MainWindow()
{
InitializeComponent();
_state = new State((bool)checkBox.IsChecked);
this.DataContext = _state;
}
Though, personally, I'm not sure I'd bother with the constructor. You appear to have no other code that would set checkBox.IsChecked, so it seems to me that you're always going to get the default value anyway. Besides, you can't create your view model class in XAML if it doesn't have a parameterized constructor; in the future, you may prefer to configure your DataContext like that. E.g.:
<Window.DataContext>
<l:State Checked="True"/>
</Window.DataContext>
And in the window's constructor:
public MainWindow()
{
InitializeComponent();
_state = (State)this.DataContext;
}
See also the related Q&A Automatically INotifyPropertyChanged. The question there is really about something different — they want to implement the interface without having to explicitly write anything in the property setter — but for better or worse, the answers they got are really more about your scenario, where it's just a question of simplifying the property setter implementation rather than making it completely automatic.
I have to admit, I would've thought there would have been another question already with which to mark yours as a duplicate. And I did find lots of related questions. But nothing that focuses directly on just "how do I implement and use a view model that implements INotifyPropertyChanged?", which is really what your question seems to be about.
Addendum:
I did some more searching, and while none of these seem like they would be considered exact duplicates per se, they all have good information that help address the question about implementing INotifyPropertyChanged:
Use of Attributes… INotifyPropertyChanged
INotifyPropertyChanged for model and viewmodel
BindableBase vs INotifyChanged
How to write “ViewModelBase” in MVVM (WPF)
You are real close. You need to make 2 small changes and your test works:
Assign the DataContext of your Window to the _state variable.
Put the string "Checked" into the OnPropertyChanged and pass propertyName to the PropertyChangedEventArgs in the OnPropertyChanged method.
So your MainWindow ctor becomes:
public MainWindow()
{
InitializeComponent();
_state = new State((bool)checkBox.IsChecked);
this.DataContext = _state;
}
and the State class file looks like:
class State : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _checked;
public bool Checked
{
get
{
return _checked;
}
set
{
_checked = value;
OnPropertyChanged("Checked");
}
}
public void Toggle()
{
if (!Checked)
{
Checked = true;
}
else
{
Checked = false;
}
}
public State(bool c)
{
this.Checked = c;
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
As a novice, I recommend you learn more about Model-View-ViewModel MVVM Design Pattern. It is a common pattern with WPF and helps encourage separation of concerns (keeping your business logic out of your user interface logic)
The OnPropertyChanged method expects the Checked property's name as argument - at the moment, you're passing its value!
This means, change the Checked property declaration to:
public bool Checked {
get
{
return _checked;
}
set
{
_checked = value;
OnPropertyChanged("Checked");
}
}

Raise an event in main whenever a variable's value changed in a class in c#?

I have a changed event in a class, which is triggered at a variable's value change but I dont know how to send a notification to the main of my C# windows form, for example, show a message box to notify the value changed. I dont wanna set a timer to check every second for a response. There is any better way?
You are probably looking for INotifyPropertyChanged, a common pattern in WPF but it can also be used for Windows Forms. There is a pretty large example on the documentation page:
https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx
class SomeClass : INotifyPropertyChanged
{
private int foo;
public event PropertyChangedEventHandler PropertyChanged;
public int Foo
{
get { return foo; }
set
{
if (foo == value)
return;
foo = value;
PropertyChanged("Foo");
}
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Please note that much of this becomes safer and much less boilerplate you use newer .NET features such as [CallerMemberName]
As other posted you should impement INotifyPropertyChanged, but in addition I would suggest the following as well:
In the setter of your property check whether the value, that is assigned to your property really changes the property's value. Otherwise you probably fire the notify change to often.
You should also implement ISupportInitialize. Usually, you fire the property changed event to inform your main form that data has changed and needs to be saved. But if you load your instances from e.g. a database, the property changed event would also fire, indicating data has changed, which is not true in that sense. With ISupportInitialize you can tell your instances that they are being initialized and that they should not fire the notify property changed event.
Here is some sample code:
class MyTest : INotifyPropertyChanged, ISupportInitialize
{
public event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e);
private bool _IsInitializing;
private bool _MyProperty;
public void BeginInit()
{
_IsInitializing = true;
}
public void EndInit()
{
_IsInitializing = false;
}
public bool MyProperty {
get { return _MyProperty; }
set {
if (_MyProperty == value)
return;
_MyProperty = value;
OnPropertyChanged("MyProperty");
}
}
private void OnPropertyChanged(string propertyName)
{
if (_IsInitializing)
return;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
For initialization you would write (to prevent the property changed event from firering):
MyTest thisTest = new MyTest();
thisTest.BeginInit();
thisTest.MyProperty = true;
thisTest.EndInit();
You should wrap your variable with a "Property" (Getter and Setter).
Then you can implement in the "Setter" either your own event, or you can trigger the property changed event from WPF (if you are using WPF).

Windows Store App Development - InvalidateRequerySuggested

in regular WPF projects I've used
CommandManager.InvalidateRequerySuggested();
in order to force a value converter to be executed again.
Now, in Windows Store App development this handy command is no longer available.
Does an equivalent command or something else, which does the trick, exist?
Thanks a lot for your help!
The CommandManager doesn't exist in WinRT. You need to manually refresh listeners. Here's my example implementation of DelegateCommand<T> that illustrates this:
using System;
using System.Windows.Input;
public class DelegateCommand<T> : ICommand
{
private readonly Action<T> m_executeAction;
private readonly Predicate<T> m_canExecutePredicate;
public DelegateCommand(Action<T> executeAction)
: this(executeAction, null)
{
}
public DelegateCommand(Action<T> executeAction, Predicate<T> canExecutePredicate)
{
if (executeAction == null)
{
throw new ArgumentNullException("executeAction");
}
m_executeAction = executeAction;
m_canExecutePredicate = canExecutePredicate;
}
public event EventHandler Executed;
public event EventHandler CanExecuteChanged;
bool ICommand.CanExecute(object parameter)
{
return CanExecute((T)parameter);
}
void ICommand.Execute(object parameter)
{
Execute((T)parameter);
}
public bool CanExecute(T parameter)
{
var result = true;
var canExecutePredicate = m_canExecutePredicate;
if (canExecutePredicate != null)
{
result = canExecutePredicate(parameter);
}
return result;
}
public void Execute(T parameter)
{
m_executeAction(parameter);
RaiseExecuted();
}
public void Refresh()
{
RaiseCanExecuteChanged();
}
protected virtual void RaiseExecuted()
{
var handler = Executed;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
protected virtual void RaiseCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
The WPF version of this class indirectly uses CommandManager.InvalidateRequerySuggested by implementing CanExecuteChanged as follows:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
However, in WinRT this is not supported and in my WinRT version any code that invalidates the state of the delegate command must call the Refresh method to cause bound items in the view to requery the command.
I think the best solution to your specific problem would be to implement INotifyPropertyChanged in your view model. Invoking the PropertyChanged event on this interface is equivalent to my Refresh method and forces bound elements in the view to re-evaluate themselves and, thus, to re-run all associated IValueConverter instances.
According to Microsoft Developer Network it does work with Windows 8 and Framework 4.5. However, it does state the following:
The CommandManager only pays attention to certain conditions in
determining when the command target has changed, such as change in
keyboard focus. In situations where the CommandManager does not
sufficiently determine a change in conditions that cause a command to
not be able to execute, InvalidateRequerySuggested can be called to
force the CommandManager to raise the RequerySuggested event.
But since it doesn't mention Windows Mobile for Windows Devices below WinRT being compliant that above command may not work for those devices, but if it is for Windows Store for WinRT and Windows 8 it should work just fine.
If I misunderstood your question please let me know and I'll try to assist further.
Article about command here:

Is my approach to assign values to an instance of custom EventArgs recommended?

In my current situation I have a class that performs an operation synchronously. During that operation an certain event will the thrown several times, depending on how often the situation where the event is raised occurs.
I know how the event-mechanism works and what the recommended ways of using are. Works well.(Note: My application is single-threaded)
What I want to is, to set a value to a property in my EventArgs. I've never had the need to set properties there.
This is a simplified situation of my current situation: (Note, I don't need answers telling me to use regex, or stringreplace, because that won't work in this situation)
I have this EventArgs:
public class TestEventArgs : EventArgs
{
public String OldString { get; private set; }
public String NewString { get; set; }
public TestEventArgs(String oldString)
{
this.OldString = oldString;
}
}
I do normally raise events this way:
public event EventHandler<TestEventArgs> ChangeString;
protected virtual void OnChangeString(String oldString)
{
EventHandler<TestEventArgs> handler = this.ChangeString;
if (handler != null)
{
handler(this, new TestEventArgs(oldString));
}
}
and by calling the OnChangeString method, because I read that this in the way to raise events a long time ago.
Modified code where I need a value of the EventArgs after it's been raised:
public event EventHandler<TestEventArgs> ChangeString;
protected virtual void OnChangeString(TestEventArgs args)
{
EventHandler<TestEventArgs> handler = this.ChangeString;
if (handler != null)
{
handler(this, args);
}
}
public void Foo()
{
String oldString = "this is the old string";
// this.OnChangeString(oldString) // this is the way I called before
// now I need to keep a reference to the EventArgs
TestEventArgs args = new TestEventArgs(oldString);
this.OnChangeString(args);
// here I do have full access to args.NewString
}
So, is it ok to keep a reference for the EventArgs and to raise the event with a method that accepts my EventArgs as parameter?
I think your question boils down to:
Is it OK to use the the arguments of an event to communicate data back to the source of the event?
First and foremost: at the low level, this will work. You can modify the event object, and you can see those changes in the code that raises the event.
But what if there are multiple event listeners. Who gets to set NewString?
If you expect only one, it is more clear to pass a delegate (of type Func<String, String>) to the class that now raises the event.
If I get your question right, you generally don't want to keep a reference to your TestEventArg, and reuse this object on another event.
In your case, your TestEventArg has a public properties call NewString. If any event handler updates this property, while it is begin reference by multiple part of your program, you may accidentally running into problem where the NewString property kept changing from another part of your problem.
However, if your TestEventArg has only readable property, then I see no problem keeping the reference and reuse it.
public class TestEventArgs : EventArgs
{
public String OldString { get; private set; }
public String NewString { get; private set; }
public TestEventArgs(String oldString, String newString)
{
this.OldString = oldString;
this.NewString - newString
}
}
In general, you want to keep your event arg immutable which will makes your program easier understand and debug.
Only time I keep the TestEventArg arg (in this case) is if you need access to the variable after the method has been called. Example of this is the OnClosing event for a Form. It has a variable you can set to tell it to cancel the close. In this case, if the client registers the callback, and can set a property on the TestEventArg class, then you'd want to have a variable pointed to it. If all you want to do is pass information to the callback and don't need anything back, then the first method is what I use.
One caveat for me is that if I use the OnChangeString method, I write it so that it encapsulates the details of the event args.
protected virtual void OnChangeString(string oldString)
{
EventHandler<TestEventArgs> handler = this.ChangeString;
if (handler != null)
{
var args = new TestEventArgs(oldString);
handler(this, args);
// Do something with args
}
}

Categories

Resources