Programing

WPF 명령 새로 고침

crosscheck 2020. 11. 4. 07:41
반응형

WPF 명령 새로 고침


누구든지 내가 CanExecute사용자 지정 명령 (Josh Smith 's RelayCommand) 에 대해 강제 로 호출 할 수있는 방법을 알고 있습니까?

일반적으로 CanExecuteUI에서 상호 작용이 발생할 때마다 호출됩니다. 무언가를 클릭하면 명령이 업데이트됩니다.

나는 CanExecute장면 뒤에서 타이머에 의해 조건 이 켜지거나 꺼지는 상황 이 있습니다. 이것은 사용자 상호 작용에 의해 주도되지 않기 때문에 CanExecute사용자가 UI와 상호 작용할 때까지 호출되지 않습니다. 최종 결과는 Button사용자가 클릭 할 때까지 활성화 / 비활성화 상태로 유지됩니다. 클릭 후 올바르게 업데이트됩니다. 때때로 Button활성화 것처럼 보이지만 사용자가 클릭하면 실행되는 대신 비활성화 됨으로 변경됩니다.

타이머가 영향을 미치는 속성을 변경할 때 어떻게 코드에서 업데이트를 강제 할 수 CanExecute있습니까? 영향을주는 속성에 대해 해고 PropertyChanged( INotifyPropertyChanged)를 시도했지만 CanExecute도움이되지 않았습니다.

XAML 예 :

<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; }

CommandManager.InvalidateRequerySuggested()


오래 전에 CommandManager.InvalidateRequerySuggested ()를 알고 사용했지만 가끔씩 작동하지 않았습니다. 나는 이것이 왜 그런지 마침내 알아 냈다! 다른 액션처럼 던지지 않더라도 메인 스레드에서 호출해야합니다.

백그라운드 스레드에서 호출하면 작동하는 것처럼 보이지만 때때로 UI를 비활성화 된 상태로 둡니다. 나는 이것이 누군가에게 도움이되고 내가 방금 낭비한 시간을 절약하기를 정말로 바란다.


이에 대한 해결 방법 IsEnabled은 속성에 바인딩 하는 것입니다.

<Button Content="Button" Command="{Binding Cmd}" IsEnabled="{Binding Path=IsCommandEnabled}"/>

그런 다음 ViewModel에서이 속성을 구현합니다. 이것은 또한 UnitTesting이 특정 시점에 명령이 실행될 수 있는지 확인하기 위해 명령이 아닌 속성으로 작업하는 것을 조금 더 쉽게 만듭니다.

개인적으로 더 편리하다고 생각합니다.


아마도이 변형이 당신에게 적합 할 것입니다 :

 public interface IRelayCommand : ICommand
{
    void UpdateCanExecuteState();
}

이행:

 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();
    }
}

간단한 사용 :

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}"/>

팁 주셔서 감사합니다. 다음은 BG 스레드에서 UI 스레드로 해당 호출을 마샬링하는 방법에 대한 코드입니다.

private SynchronizationContext syncCtx; // member variable

생성자에서 :

syncCtx = SynchronizationContext.Current;

백그라운드 스레드에서 재 쿼리를 트리거하려면 :

syncCtx.Post( delegate { CommandManager.InvalidateRequerySuggested(); }, null );

도움이되기를 바랍니다.

-마이클


GalaSoft.MvvmLight.CommandWpf.RelayCommand를 하나만 업데이트하려면 다음을 사용할 수 있습니다.

mycommand.RaiseCanExecuteChanged();

나를 위해 Extension 메서드를 만들었습니다.

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(); }));
        }
    }

참고 URL : https://stackoverflow.com/questions/783104/refresh-wpf-command

반응형