[英]How can I update progress bar value in WPF MVVM
我的問題是如果我只需要調用我的方法一次,如何在進度條上顯示進度? 我正在 WPF 中處理 MVVM 項目。 我必須在進度條上顯示我的循環進度。 如果我在 Model 類中有類似的東西,我的 ProgressBar 會正確更新,但只有一次
public double progressBarValue;
public string inputText;
public int quantityOfNumbers
{
get;
set;
}
public void inputTextToInt(string inputText)
{
progressBarValue = Convert.ToInt32(inputText);
quantityOfNumbers = Convert.ToInt32(inputText);
//work();
}
但是,如果我嘗試使用以下代碼實時更新我的進度條:
public void inputTextToInt(string inputText)
{
//progressBarValue = Convert.ToInt32(inputText);
quantityOfNumbers = Convert.ToInt32(inputText);
work();
}
private async void work()
{
RandNumbers randNumbers = new RandNumbers(quantityOfNumbers);
var progress = new Progress<double>(value =>
{
progressBarValue = value;
Console.WriteLine(progressBarValue);
});
await Task.Run(() => randNumbers.RandAllNumbers(progress));
}
我的 ProgressBar 沒有任何進展。 我已經檢查了控制台,在這一行中我的 progressBarValue 正在正確更改但它沒有發送到我的 ViewModel 類。
progressBarValue = value;
這是我的 ViewModel 類:
private ModelTME_App model = new ModelTME_App();
public string inputText
{
get { return model.inputText; }
set { model.inputText = value;
onPropertyChanged(nameof(inputText));
}
}
public double progressBarValue
{
get {
Console.WriteLine(model.progressBarValue);
return model.progressBarValue;
}
}
private ICommand inputTextToInt = null;
public ICommand InputTextToInt
{
get
{
if(inputTextToInt == null)
{
inputTextToInt = new RelayCommand(
(object o) =>
{
model.inputTextToInt(inputText);
onPropertyChanged(nameof(progressBarValue));
},
(object o) =>
{
return model.progressBarValue == 0;
});
}
return inputTextToInt;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void onPropertyChanged(string nameOfProperty)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(nameOfProperty));
}
}
}
我的 RelayCommandClass
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
if (execute == null)
{
throw new ArgumentNullException(nameof(execute));
}
else
{
this.execute = execute;
}
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public bool CanExecute(object parameter)
{
if(canExecute == null)
{
return true;
}
else
{
return canExecute(parameter);
}
}
public void Execute(object parameter)
{
execute(parameter);
}
}
Binding.Source
必須始終引發INotifyPropertyChanged.PropertyChanged
事件以觸發Binding
更新Binding.Target
。
您應該避免通過委托屬性綁定到模型。 模型不應公開 API 以允許這樣做(數據隱藏)。
正確的模式是在視圖模型可以觀察到的模型中實現ProgressChanged
事件。
還要避免一些代碼異味:
永遠不要從async
方法返回void
,除非該方法是事件處理程序。 async
方法必須返回Task
或Task<T>
。 返回的Task
必須在調用鏈上傳播並等待。
避免在 lambda 中捕獲成員變量。 在某些情況下,這可能會造成內存泄漏
使用方法將值從View Model傳遞到Model 。 將所有模型屬性暴露給視圖模型會暴露太多信息細節(例如設置哪些屬性以將模型更改為有效狀態)。 而是讓公共方法請求所需的數據作為參數或參數對象。 屬性應該是私有的(配置對象所需的屬性除外)。
使用ProgressBar...
或InputText...
等成員和參數名稱會提示您的模型設計不正確。 由於模型不知道視圖,因此它對進度條或輸入文本也不感興趣。 可能是簡單的命名問題或嚴重的設計問題。
您應該嘗試實施官方的 C# 命名指南
模型.cs
ProgressChanged
事件是使用ProgressChangedEventArgs
定義的。
class Model
{
public event EventHandler<ProgressChangedEventArgs> ProgressChanged;
private double ProgressPercentage { get; set; }
private string NumericText { get; set; }
private int QuantityOfNumbers { get; set; }
protected virtual void OnProgressCHanged(double percentage)
=> this.ProgressChanged?.Invoke(new ProgressChangedEventArgs(percentage, string.Empty);
public async Task<int> ToIntAsync(string numericText)
{
NumericText = numericText;
QuantityOfNumbers = Convert.ToInt32(NumericText);
await WorkAsync();
return QuantityOfNumbers;
}
private async Task WorkAsync()
{
// Can you guarantee that this method is called from the UI thread?
var progress = new Progress<double>(value =>
{
ProgressPercentage = value;
Console.WriteLine(ProgressBarValue);
OnProgressChanged(ProgressBarValue);
});
// Avoid capturing member variables in lambdas
int quantityOfNumbers = QuantityOfNumbers;
await Task.Run(() =>
{
var randNumbers = new RandNumbers(quantityOfNumbers);
randNumbers.RandAllNumbers(progress));
});
}
}
視圖模型.cs
class ViewModel : INotifyPropertyChanged
{
private Model _model;
// TODO::Let property raise PropertyChanged event
public double ProgressValue { get; set; }
public ICommand InputTextToIntCommand => new RelayCommand(ExecuteInputTextToIntCommandAsync);
// TODO::Let property raise PropertyChanged event
public string NumericText { get; set;}
public ViewModel()
{
_model = new Model();
}
// Make sure RelayCommand can execute async delegates
private async Task ExecuteInputTextToIntCommandAsync()
{
_model.PropgressChnaged += OnProgressChanged;
// Pass value to model
var quantityOfNumbersResult = await _model.ToIntAsync(this.NumericText);
}
private void OnProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ProgressValue = e.ProgressPercentage;
if (this.ProgressValue >= 100)
{
_model.PropgressChnaged -= OnProgressChanged;
}
}
}
一個允許取消的簡單異步命令實現(基於發布的示例):
public class RelayCommand : ICommand
{
private CancellationTokenSource cancellationTokenSource;
private readonly Func<object, Task> executeAsync;
private readonly Func<object, CancellationToken, Task> executeCancellableAsync;
private Action<object> execute;
private Func<object, bool> canExecute;
public RelayCommand(Func<object, CancellationToken, Task> executeCancellableAsync, Func<object, bool> canExecute)
{
this.executeCancellableAsync = executeCancellableAsync;
this.canExecute = canExecute;
}
public RelayCommand(Func<object, Task> executeAsync, Func<object, bool> canExecute)
{
this.executeAsync = executeAsync;
this.canExecute = canExecute;
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
if (execute == null)
{
throw new ArgumentNullException(nameof(execute));
}
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public bool CanExecute(object parameter)
{
return canExecute?.Invoke(parameter) ?? true;
}
public void Execute(object parameter)
{
_ = ExecuteAsync(parameter);
}
public async Task ExecuteAsync(object commandParameter)
{
using (this.cancellationTokenSource = new CancellationTokenSource())
{
await ExecuteAsync(commandParameter, this.cancellationTokenSource.Token);
}
}
public Task ExecuteAsync(object commandParameter, CancellationToken cancellationToken)
{
if (this.executeCancellableAsync is not null)
{
return this.executeCancellableAsync.Invoke(commandParameter, cancellationToken);
}
else if (this.executeAsync is not null)
{
return this.executeAsync.Invoke(commandParameter);
}
else
{
this.execute.Invoke(commandParameter);
return Task.CompletedTask;
}
}
public void Cancel()
{
this.cancellationTokenSource?.Cancel();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.