Frage
Wer weiß, wie ich Beispiel-Code hinter: CanExecute
zwingen kann, auf einem benutzerdefinierten Befehl (Josh Smith <Button Content="Button" Command="{Binding Cmd}"/>
private ICommand m_cmd;
public ICommand Cmd
{
if (m_cmd == null)
m_cmd = new RelayCommand(
(param) => Process(),
(param) => EnableButton);
return m_cmd;
}
// Gets updated from a timer (not direct user interaction)
public bool EnableButton { get; set; }
Andere Tipps
Ich war bewusst CommandManager.InvalidateRequerySuggested () vor langer Zeit, und verwenden es, aber es funktioniert nicht manchmal für mich. Ich endlich herausgefunden, warum dies der Fall war! Auch wenn es wie einige andere Aktionen nicht werfen, haben Sie es auf dem Hauptthread zu nennen.
es auf einem Hintergrund-Thread aufrufen erscheint, zu arbeiten, aber manchmal die Benutzeroberfläche deaktiviert lassen. Ich hoffe wirklich, dass dies jemand hilft, und speichert sie die Stunden, die ich nur verschwendet.
Eine Abhilfe für das verbindlich IsEnabled
auf eine Eigenschaft:
<Button Content="Button" Command="{Binding Cmd}" IsEnabled="{Binding Path=IsCommandEnabled}"/>
und dann diese Eigenschaft in Ihrem Ansichtsmodell implementieren. Dies macht es auch ein bisschen einfacher für den Unittesting mit den Eigenschaften zu arbeiten, anstatt Befehlen zu sehen, ob der Befehl zu einem bestimmten Zeitpunkt ausgeführt werden kann.
Ich persönlich finde es bequemer.
Wahrscheinlich wird diese Variante zu Ihnen passen:
public interface IRelayCommand : ICommand
{
void UpdateCanExecuteState();
}
Umsetzung:
public class RelayCommand : IRelayCommand
{
public event EventHandler CanExecuteChanged;
readonly Predicate<Object> _canExecute = null;
readonly Action<Object> _executeAction = null;
public RelayCommand( Action<object> executeAction,Predicate<Object> canExecute = null)
{
_canExecute = canExecute;
_executeAction = executeAction;
}
public bool CanExecute(object parameter)
{
if (_canExecute != null)
return _canExecute(parameter);
return true;
}
public void UpdateCanExecuteState()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, new EventArgs());
}
public void Execute(object parameter)
{
if (_executeAction != null)
_executeAction(parameter);
UpdateCanExecuteState();
}
}
einfache Verwendung:
public IRelayCommand EditCommand { get; protected set; }
...
EditCommand = new RelayCommand(EditCommandExecuted, CanEditCommandExecuted);
protected override bool CanEditCommandExecuted(object obj)
{
return SelectedItem != null ;
}
protected override void EditCommandExecuted(object obj)
{
// Do something
}
...
public TEntity SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
//Refresh can execute
EditCommand.UpdateCanExecuteState();
RaisePropertyChanged(() => SelectedItem);
}
}
XAML:
<Button Content="Edit" Command="{Binding EditCommand}"/>
Danke Jungs für die Tipps. Hier ist ein Stück Code wie dieser Anruf Marschall von einem BG Thread zu dem UI-Thread:
private SynchronizationContext syncCtx; // member variable
Im Konstruktor:
syncCtx = SynchronizationContext.Current;
Auf dem Hintergrund-Thread, die requery auslösen:
syncCtx.Post( delegate { CommandManager.InvalidateRequerySuggested(); }, null );
Ich hoffe, das hilft.
- Michael
Um nur einen einzigen GalaSoft.MvvmLight.CommandWpf.RelayCommand aktualisieren könnten Sie
mycommand.RaiseCanExecuteChanged();
und für mich ich habe eine Erweiterungsmethode erstellt:
public static class ExtensionMethods
{
public static void RaiseCanExecuteChangedDispatched(this RelayCommand cmd)
{
System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
}
public static void RaiseCanExecuteChangedDispatched<T>(this RelayCommand<T> cmd)
{
System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
}
}