[英]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.