Windows Store App Development - InvalidateRequerySuggested - c#

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:

Related

Is a command a sort of event handler or why does my button execute the command?

I'm learning about wpf, delegates, event and I have some clue on what does what, but I'm a little lost when it comes to implementing ICommand
I have a class the implements the ICommand interface like this
class RelayCommand : ICommand
{
private Action<object> _execute;
private Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute) : this (execute, null)
{
}
public RelayCommand(Action<object> execute, Func<object,bool> canExecute)
{
this._execute = execute;
this._canExecute = canExecute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
//throw new NotImplementedException();
return true;
}
public void Execute(object parameter)
{
//throw new NotImplementedException();
this._execute(parameter);
}
public void OnCanExecute()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
And then my ViewModel that uses i.
class PersonViewModel
{
public ICommand ICommandPresenter { get; set; }
public PersonModel PM;
private string _btnString = "";
#region Propertys
public string ButtonString
{
get {return _btnString; }
set
{
if (_btnString.Equals(value))
{
return;
}
_btnString = value;
}
}
public string Name { get { return PM.Name; } set
{
PM.Name = value;
}
}
#endregion Propertys
public PersonViewModel()
{
PM = new PersonModel();
ICommandPresenter = new RelayCommand(ChangeName);
}
public void ChangeName(object a)
{
string s = a as string;
MessageBox.Show("Hello from PersonViewModel Commander: " + s);
}
}
This is where it gets confusing for me. In the RelayCommand class I have an event CanExecuteChanged but that event is never executed/fired. From what I've understood from my reading on events is that you don't "need" to have subscribers to an event, but if you're going to have an event you should atleast have somewhere in the code that executes it. But I don't have that in my code but for some reason my button still does what I command it to do. I still understand that I've clicked the button but I don't have anything in my code that is subscribed to that button.
Why is my button able to execute my code even though I don't have an event connected to it?
Since I don't have any subscribers connected to CanExecuteChanged event does it becomes useless?
Is the command acting like an event? if so, please describe the whole process from clicking the button to executing the command.
CanExecuteChanged is member of ICommand class and, simplifying the things, is used by wpf framework to enable/disable your button depending on result of CanExecute() method. CanExecute is not tight to the code you want to execute when you click the button, but to the condition, when it's legal to be done.
Command executes your code, because you send pointer to your method(ChangeName method) here:
ICommandPresenter = new RelayCommand(ChangeName);
So you are not using CanExecuteChange at all, because you are invoking this constructor:
public RelayCommand(Action<object> execute).
To have CanExecute you have to invoke overloaded constructor that accepts CanExecute predicate:
public RelayCommand(Action<object> execute, Func<object,bool> canExecute)
And to invoke it just pass some function that returns a bool as second parameter:
ICommandPresenter = new RelayCommand(ChangeName, ()=>MyCustomLogicWhenButtonIsActive());
Based on what I saw in .Net's source code, the command assigned to the button's Command property is executed in the following way:
Clicking the button calls the button's OnClick() method (located in the button's ButtonBase base class).
The OnClick() method (see source here) calls the Commands.CommandHelpers.ExecuteCommandSource() method, passing this as the command source parameter.
The ExecuteCommandSource() (see source here) further calls the CriticalExecuteCommandSource() method, passing the same command source as a parameter.
Finally, the CriticalExecuteCommandSource() method (see source here) accesses the command source's Command member, and:
checks if the command's CanExecute() method returns true,
if it's true, it calls the command's Execute() method.
(If you use a RelayCommand implementation, then obviously, the RelayCommand class relays the call to the specific method you passed to its constructor when you instantiated it.)
So, to answer your question whether commands are fired through an event:
The source indicates that the OnClick() method executes the command directly, not through event handling. As you can see in the source, this method does raise the Click event, but it does so separately from the command execution.
Though, it remains unanswered how the OnClick() method is being called in the first place by the framework; I have no idea about that.

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 (8.1): INotifyPropertyChanged Must Be Top Level?

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.

Monitor a change in the property of a Telerik ScheduleView control in WPF

I have 2 properties to a class (WPF control): HorizontalOffset and VerticalOffset (both public Double's). I would like to call a method whenever these properties change. How can I do this? I know of one way - but I'm pretty sure it's not the right way (using a DispatcherTimer of very short tick intervals to monitor the property).
EDIT FOR MORE CONTEXT:
These properties belong to a telerik scheduleview control.
Leverage the INotifyPropertyChanged interface implementation of the control.
If the control is called myScheduleView:
//subscribe to the event (usually added via the designer, in fairness)
myScheduleView.PropertyChanged += new PropertyChangedEventHandler(
myScheduleView_PropertyChanged);
private void myScheduleView_PropertyChanged(Object sender,
PropertyChangedEventArgs e)
{
if(e.PropertyName == "HorizontalOffset" ||
e.PropertyName == "VerticalOffset")
{
//TODO: something
}
}
I know of one way ... DispatcherTimer
Wow avoid that :) INotifyPropertyChange interface is your friend. See the msdn for samples.
You basically fire an event(usually called onPropertyChanged) on the Setter of your properties and the subscribers handle it.
an example implementation from the msdn goes:
// This is a simple customer class that
// implements the IPropertyChange interface.
public class DemoCustomer : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
public string CustomerName
{
//getter
set
{
if (value != this.customerNameValue)
{
this.customerNameValue = value;
NotifyPropertyChanged("CustomerName");
}
}
}
}

INotifyPropertyChanged with threads

I have a
BindingList<T>
which is bound to a datagridview. One property in my class takes long to calculate, so I threaded the action. After the calculation I raise the OnPropertyChanged() event to notify the grid that the value is ready.
At least, that's the theory. But since the OnPropertyChanged Method is called from a differend thread I get some weired exceptions in the OnRowPrePaint method of the grid.
Can anybody tell me how I fore the OnPropertyChanged event to be excecuted in the main thread? I can not use Form.Invoke, since the class MyClass is not aware that it runs in a Winforms application.
public class MyClass : INotifyPropertyChanged
{
public int FastMember {get;set;}
private int? slowMember;
public SlowMember
{
get
{
if (slowMember.HasValue)
return slowMember.Value;
else
{
Thread t = new Thread(getSlowMember);
t.Start();
return -1;
}
}
}
private void getSlowMember()
{
Thread.Sleep(1000);
slowMember = 5;
OnPropertyChanged("SlowMember");
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangingEventHandler eh = PropertyChanging;
if (eh != null)
{
eh(this, e);
}
}
}
People sometimes forget that the event handler is a MultiCastDelegate and, as such, has all the information regarding each subscriber that we need to handle this situation gracefully without imposing the Invoke+Synchronization performance penalty unnecessarily. I've been using code like this for ages:
using System.ComponentModel;
// ...
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
foreach (EventHandler h in handler.GetInvocationList())
{
var synch = h.Target as ISynchronizeInvoke;
if (synch != null && synch.InvokeRequired)
synch.Invoke(h, new object[] { this, e });
else
h(this, e);
}
}
}
What it does is simple, but I remember that I almost cracked my brain back then trying to find the best way to do it.
It first "grabs" the event handler on a local property to avoid any race conditions.
If the handler is not null (at lease one subscriber does exist) it prepares the event args, and then iterates through the invocation list of this multicast delegate.
The invocation list has the target property, which is the event's subscriber. If this subscriber implements ISynchronizeInvoke (all UI controls implement it) we then check its InvokeRequired property, and it is true we just Invoke it passing the delegate and parameters. Calling it this way will synchronize the call into the UI thread.
Otherwise we simply call the event handler delegate directly.
By design, a control can only be updated by the thread it was created in. This is why you are getting exceptions.
Consider using a BackgroundWorker and only update the member after the long lasting operation has completed by subscribing an eventhandler to RunWorkerCompleted.
Here's something I wrote a while ago; it should work reasonably well, but note the cost of lots of updates...
using System.ComponentModel;
using System.Threading;
public class ThreadedBindingList<T> : BindingList<T> {
SynchronizationContext ctx = SynchronizationContext.Current;
protected override void OnAddingNew(AddingNewEventArgs e) {
if (ctx == null) { BaseAddingNew(e); }
else { ctx.Send(delegate { BaseAddingNew(e); }, null); }
}
protected override void OnListChanged(ListChangedEventArgs e) {
if (ctx == null) { BaseListChanged(e); }
else { ctx.Send(delegate { BaseListChanged(e); }, null); }
}
void BaseListChanged(ListChangedEventArgs e) { base.OnListChanged(e); }
void BaseAddingNew(AddingNewEventArgs e) { base.OnAddingNew(e); }
}
Consideration 1:
Take a look at UIThreadMarshal class and its usage in this article:
UI Thread Marshaling in the Model Layer
You can change the class from static to instance and inject it into your object. So your object will not know about Form class. It will know only about UIThreadMarshal class.
Consideration 2:
I don't think returning -1 from your property is good idea. It looks like a bad design to me.
Consideration 3:
Maybe your class shouldn't use antoher thread. Maybe it's consumer classes who should decide how to call your property: directly or in a separate thread. In this case maybe you need to provide additional property, such as IsSlowMemberInitialized.

Categories

Resources