#c_sharp #wpf
Иногда кнопка после выполнения команды не становится активной. Помогает клик по форме. Скажете пожалуйста в чем может быть проблема? XAML: C#: private readonly RaiseCommand doneCommand; private readonly BackgroundWorker worker; private object _currentUserState; private int _currentProgress; public RaiseCommand DoneCommand { get { return doneCommand; } } public MainWindowViewModel() { doneCommand = new RaiseCommand(o => worker.RunWorkerAsync(), o => !worker.IsBusy); worker = new BackgroundWorker(); worker.DoWork += DoDoneCommand; worker.ProgressChanged += ProgressChanged; worker.RunWorkerCompleted += RunWorkerCompleted; worker.WorkerReportsProgress = true; } private void DoDoneCommand(object sender, DoWorkEventArgs e) { MessageBox.Show("test"); } private void ProgressChanged(object sender, ProgressChangedEventArgs e) { CurrentUserState = e.UserState; CurrentProgress = e.ProgressPercentage; } private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { } Класс RaiseCommand: public class RaiseCommand : ICommand { readonly Action
Ответы
Ответ 1
Без клика по окну не обновляется состояние кнопки и не вызывается CanExecute, соответственно, кнопка остается неактивной. Обновленный ответ: Для явного обновления интерфейса вручную можете попробовать вызвать CommandManager.InvalidateRequerySuggested по завершении потока: private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { CommandManager.InvalidateRequerySuggested(); } Из документации: 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. Ответ до обновления: Можно попробовать явно вызвать CanExecuteChanged после завершения BackgroundWorker. Для этого в комманду добавляем свое событие и метод его вызова: //объявляем событие private event EventHandler InternalCanExecuteChanged; //привязываем его к CanExecuteChanged public event EventHandler CanExecuteChanged { add { InternalCanExecuteChanged += value; CommandManager.RequerySuggested += value; } remove { InternalCanExecuteChanged -= value; CommandManager.RequerySuggested -= value; } } //метод для вызова public void RaiseCanExecuteChanged() { var handler = InternalCanExecuteChanged; if (handler != null) handler(this, EventArgs.Empty); } и обращаемся к методу после завершения потока: private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { doneCommand.RaiseCanExecuteChanged(); }Ответ 2
Позволю себе написать ответ, хотя он только косвенно относится к озвученному вопросу. Если вы хотите блокировать активность кнопки до тех пор пока некоторая длительная операция будет завершена, то возможно правильным решением будет воспользоваться асинхронными командами вместо того, чтобы применять немного устаревший BackgroundWorker По идее асинхронные версии команд должны предоставляться основными библиотеками упрощающими разработку WPF проекты. Если по каким-то причинам вы не хотите их подключать, то можно найти реализации AsyncCommand в интернете. Например, отличная статья Async Programming : Patterns for Asynchronous MVVM Applications: Commands Чтобы ответ был более полным приведу пример тривиального таймера обратного отсчета, когда мы не можем (не должны) запускать новый до истечения предыдущего. Разметкаи контекст let source = Bind.createSource() let step = 1000 let startInt = 10 let Count = Mutable.create startInt let start _ = async { while Count.Value > 0 do do! Async.Sleep step Mutable.step (fun x -> x - 1) Count return startInt } Bind.Explicit.oneWay source "Count" Count Bind.Explicit.createCommand "Start" source |> Observable.mapAsyncTracked start source.IdleTracker |> Observable.subscribe (Mutable.set Count) |> source.AddDisposable При написании использована библиотека Gjallarhorn.Bindable.Wpf
Комментариев нет:
Отправить комментарий