I have written a CanExecute method for the DelegateCommand. CanExecute is not being re-evaluated as other commands which inherites from a CommandBase, that looks like this.
public abstract class CommandBase : ICommand
{
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
public virtual bool CanExecute(object parameter)
{
return true;
}
public abstract void Execute(object parameter);
}
Can I make the Prism DelegateCommand work like this, so CanExecute is automatically re-evaluated when appropriate or should I manually call RaiseCanExecuteChanged() when needed?
How should the command or the command manager know that it's execution state changed? To have them know about that you need to signal this via the RaiseCanExecuteChanged method.
Related
I have a strange issue of getting null exception. I created class that implements ICommand interface, I have two methods.
public void Execute(object parameter)
{
NavigateAsync();
}
private async void NavigateAsync()
{
await App.MainNavigation.PushAsync(new Pages.SettingsPage());
}
When NavigateAsync() is exectude my MainNavigation is always null, even that I can see that parameter inside Execute is set.
In my App.xaml.cs file I have created public static INavigation MainNavigation { get; set; }
public partial class App : Application
{
public static ViewModels.MainViewModel ViewModel { get; set; }
public static INavigation MainNavigation { get; set; }
public App ()
{
InitializeComponent();
MainPage = new NavigationPage(new Paperboy.MainPage());
}
protected override void OnStart ()
{
// Handle when your app starts
}
protected override void OnSleep ()
{
// Handle when your app sleeps
}
protected override void OnResume ()
{
// Handle when your app resumes
}
}
Se when clicking icon i can se that command is executed but App.MainNavigation inside NavigateAsync() in null. So command is not executing PushAsync to SettingsPage.
You never instantiate your static MainNavigation property...
If I can give you 2 remarks:
instead of using a static property declared into your App.xaml.cs, maybe a better implementation could be to embed a Navigation getter into a specific 'service' class or directly into your Command definition:
public class MyCommand : ICommand
{
...
// Navigation getter
// There are better places for this prop but it's better
// than in app.xaml.cs
private INavigation MainNavigation
{
get => Application.Current?.MainPage?.Navigation;
}
public void Execute(object parameter)
{
NavigateAsync();
}
private async void NavigateAsync()
{
try
{
await MainNavigation?.PushAsync(new Pages.SettingsPage());
}
catch(){ ... }
}
}
Another point I would like to note, is that your Command looks like asynchronous. Maybe you already know, but here is a good implementation of async commands to avoid app crashes: Asynchronous commands
I hope it can help you. Happy coding !
I have the following sample TFS CheckIn Policy:
[Serializable()]
public class AuditControlsPolicy : PolicyBase
{
public List<string> list;
public AuditControlsPolicy() : base()
{
list = new List<string>() { "a", "b", "c" };
System.Windows.Forms.MessageBox.Show("in constructor");
}
public override string Description
{
get { return "my description"; }
}
public override string Type
{
get { return "my policy"; }
}
public override string TypeDescription
{
get { return "description"; }
}
public override string InstallationInstructions
{
get { return "install instructions"; }
}
public override Microsoft.TeamFoundation.VersionControl.Client.PolicyFailure[] Evaluate()
{
List<PolicyFailure> policyFailures = new List<PolicyFailure>();
if (list == null)
System.Windows.Forms.MessageBox.Show("list is null");
else
System.Windows.Forms.MessageBox.Show(String.Join(",", list.ToArray()));
return policyFailures.ToArray();
}
public override void DisplayHelp(PolicyFailure failure)
{
MessageBox.Show("No help available at this time");
}
public override void Activate(PolicyFailure failure)
{
MessageBox.Show(failure.Message);
}
protected override void OnPolicyStateChanged(PolicyFailure[] failures)
{
base.OnPolicyStateChanged(failures);
}
public override void Initialize(IPendingCheckin pendingCheckin)
{
base.Initialize(pendingCheckin);
pendingCheckin.PendingChanges.CheckedPendingChangesChanged += PendingCheckinCheckedPendingChangesChanged;
}
public override void Dispose()
{
PendingCheckin.PendingChanges.CheckedPendingChangesChanged -= PendingCheckinCheckedPendingChangesChanged;
base.Dispose();
}
private void PendingCheckinCheckedPendingChangesChanged(object sender, EventArgs e)
{
OnPolicyStateChanged(Evaluate());
}
public override bool Edit(IPolicyEditArgs policyEditArgs)
{
return true;
}
}
It is properly registered and "works" -- however, it appears that the instance member field list is not initialized when the Evaluate method is called.
When I toggle to Pending Changes view in Visual Studio with at least one pending change I get the message box of "In Constructor" multiple times. This is followed by "list is null", even though I clearly initialize the field in my instance constructor. If I declare my list as a static and initialize it in the instance constructor, then it display my list of values.
It almost seems as if Visual Studio is invoking the Evaluate method on a static object, even though it is not declared as such.
Is the Evaluate method being invoked as a static? Am I missing something about how I should be constructing my Policy Object?
Evaluate method shouldn't be invoked on a static class and the Visual Studio also will not invoke the Evaluate method on a static object. There must be something wrong in your code, try to move list = new List<string>() { "a", "b", "c" }; to public override void Initialize(IPendingCheckin pendingCheckin) and try again.
According to your description and code, guess the Evaluate() method had being invoked on the parent class PolicyBase before AuditControlsPolicy, that's why you got the list is nul.
I'm changing the label in the class constructor and it works fine, the label is updated ("0"). I'm also trying to update the label when I click in a button, but it's not working ("X"). I noticed debugging that the label value is updated, PropertyChanged is triggered, but the view doesn't change.
public class HomeViewModel : ViewModelBase
{
string playerA;
public string PlayerA
{
get
{
return playerA;
}
set
{
playerA = value;
this.Notify("playerA");
}
}
public ICommand PlayerA_Plus_Command
{
get;
set;
}
public HomeViewModel()
{
this.PlayerA_Plus_Command = new Command(this.PlayerA_Plus);
this.PlayerA = "0";
}
public void PlayerA_Plus()
{
this.PlayerA = "X";
}
}
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void Notify(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The name of the parameter passed in your PropertyChangedEventArgs is wrong. You are using "playerA" but the name of the (public) property is "PlayerA" (uppercase "P"). Change this.Notify("playerA"); to this.Notify("PlayerA"); or even better:
Notify(nameof(PlayerA));
You can completely get rid of passing the name of the param by adding a [CallerMemberName] attribute to the Notify() method.
protected void Notify([CallerMemberName] string propertyName = null)
This allows you to just call Notify() without parameters and the name of the changed property will automatically be used.
I would like to know when my animation is finished, so I have to use an AnimationListener.
I cannot seem to find out how to do that in MonoDroid (C#).
Does anyone know how to do this ?
Here is a short one I wrote to get me a callback when the animation ends:
class AnimationListenerEndCallback : Java.Lang.Object, Animation.IAnimationListener
{
public delegate void Callback(Animation animation);
private Callback callback;
public AnimationListenerEndCallback(Callback callback)
{
this.callback = callback;
}
public void OnAnimationEnd(Android.Views.Animations.Animation animation)
{
callback(animation);
}
public void OnAnimationRepeat(Android.Views.Animations.Animation animation)
{
// do nothing
}
public void OnAnimationStart(Android.Views.Animations.Animation animation)
{
// do nothing
}
}
You use it like this:
Animation a = AnimationUtils.LoadAnimation(this, Resource.Animation.pull_up);
a.SetAnimationListener(new AnimationListenerEndCallback(delegate
{
// all your local variables are still in scope, so you
// can use them here
}));
I would like to update a text field instantly when typing in a GWT TextBox. My problem is that ValueChangeEvent and ChangeEvent handlers only fire when the TextBox loses focus. I thought about using the KeyPressEvent but then nothing would happen when performing a copy paste with the mouse.
What's the simplest way to do that ?
You could catch the ONPASTE event and manually fire a ValueChangeEvent. Something like this:
public void onModuleLoad() {
final Label text = new Label();
final ExtendedTextBox box = new ExtendedTextBox();
box.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
text.setText(event.getValue());
}
});
box.addKeyUpHandler(new KeyUpHandler() {
#Override
public void onKeyUp(KeyUpEvent event) {
text.setText(box.getText());
}
});
RootPanel.get().add(box);
RootPanel.get().add(text);
}
private class ExtendedTextBox extends TextBox {
public ExtendedTextBox() {
super();
sinkEvents(Event.ONPASTE);
}
#Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
switch (DOM.eventGetType(event)) {
case Event.ONPASTE:
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
ValueChangeEvent.fire(ExtendedTextBox.this, getText());
}
});
break;
}
}
}
Tested on firefox 3.6.1.
As a general solution, what works for me (thx to gal-bracha comment):
Generally, GWT does not have classes to handle input event (described here
and here). So we need to implement it by ourselves:
Handler class:
import com.google.gwt.event.shared.EventHandler;
public interface InputHandler extends EventHandler {
void onInput(InputEvent event);
}
Event class:
import com.google.gwt.event.dom.client.DomEvent;
public class InputEvent extends DomEvent<InputHandler> {
private static final Type<InputHandler> TYPE = new Type<InputHandler>("input", new InputEvent());
public static Type<InputHandler> getType() {
return TYPE;
}
protected InputEvent() {
}
#Override
public final Type<InputHandler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(InputHandler handler) {
handler.onInput(this);
}
}
Usage:
box.addDomHandler(new InputHandler() {
#Override
public void onInput(InputEvent event) {
text.setText(box.getText());
}
},InputEvent.getType());
It works on every TextBox value change including pasting using context menu. It does not react on arrows, ctrl, shift etc...
This has been a major issue for me in the past. The keyupHandler wont work because the copy paste requires a second key press on the paste option which does not fire the event. the best i have been able to do is use the old changelistener not ideal but it does work.
I prefer use Elements than Widgets so this my way to handler.
Element input = Document.get().getElementById("my-input");
DOM.sinkBitlessEvent(input, "input");
DOM.setEventListener(input, event -> GWT.log("Event!"));
Why not use combination of both KeyUpHandler and a ChangeHandler on the TextBox?
Should take care of immediate feedback on each keystroke as well as copy paste case as well.
Just saw this question. Because I was facing the similar problem.
Did some hack and it worked for me.
You can use KeyUpHandler but use it with additional if block that checks
for length of textbox. If length of text box is > 0, do your thing.
Ex:
textBox.addKeyUpHandler(new KeyUpHandler() {
#Override
public void onKeyUp(KeyUpEvent keyUpEvent) {
if (textBox.getText().length() > 0) {
//do your stuff`enter code here`
}
}