在单独 class 中从另一个方法更新用户控件内的 WPF 进度条值?
Updating WPF progress bar value inside a user control from another method in a separate class?
我是 WPF、线程和分离 UI 这个概念的新手。
所以这里我有一个设计良好的项目,其中所有计算都在一个方法内完成(例如 Command class 和 Execute 方法);用户界面包含多个用户控件。
由于计算需要几分钟,我想我应该使用 MainControl 用户控件 class.
上的进度条
所以我在MainControl中创建了这个方法来更新进度条:
public void SetProgressBar(int Value, int Min = 0, int Max = 100)
{
if (Value <= Max && Min <= Value)
{
StatusProgress.Minimum = Min;
StatusProgress.Maximum = Max;
StatusProgress.Dispatcher.Invoke(
new Action(() => this.StatusProgress.Value = Value),
System.Windows.Threading.DispatcherPriority.Background);
}
}
然后我在 Command class:
中创建了对 MainControl 的引用
private MainControl MainControlRef;
所以在我计算的不同阶段,我可以使用以下方式报告进度:
MainControlRef.SetProgressBar(10);
这是我能想到的。我认为这感觉不对。如果您能给我一些反馈,我将不胜感激。
此外,我注意到进度条有时会更新,有时不会。
使用 MVVM 模式很容易,您的 VM 通常会包含命令对象(研究 relay command)和视图所需的其他数据,例如保存进度条值的 int。
然后您的视图将绑定到此 VM,因此一旦您的命令正在执行并更新进度条值,您的视图也会更新
以下旧项目的示例,希望对您有所帮助
public class LoginViewModel : ViewModelBase
{
private static ILog Logger = LogManager.GetLogger(typeof(LoginViewModel));
#region Properties
private String _title;
private String _login;
private String _password;
private String _validationMessage;
private bool _displayLoginButton;
private bool _displayLoginProgressRing;
private bool _enableInput;
private bool _displayValidationMessage;
private ICommand _loginCommand;
public LoginViewModel()
{
DisplayLoginButton = EnableInput = true;
DisplayLoginProgressRing = DisplayValidationMessage = false;
}
public bool DisplayValidationMessage
{
get { return _displayValidationMessage; }
set
{
_displayValidationMessage = value;
RaisePropertyChanged(() => this.DisplayValidationMessage);
}
}
public bool DisplayLoginButton
{
get { return _displayLoginButton; }
set
{
_displayLoginButton = value;
RaisePropertyChanged(() => this.DisplayLoginButton);
}
}
public bool EnableInput
{
get { return _enableInput; }
set
{
_enableInput = value;
RaisePropertyChanged(() => this.EnableInput);
}
}
public bool DisplayLoginProgressRing
{
get { return _displayLoginProgressRing; }
set
{
_displayLoginProgressRing = value;
RaisePropertyChanged(() => this.DisplayLoginProgressRing);
}
}
public String Title
{
get
{
return _title;
}
set
{
_title = value;
RaisePropertyChanged(() => this.Title);
}
}
public String Login
{
get
{
return _login;
}
set
{
_login = value;
RaisePropertyChanged(() => this.Login);
}
}
public String Password
{
get
{
return _password;
}
set
{
_password = value;
RaisePropertyChanged(() => this.Password);
}
}
public String ValidationMessage
{
get
{
return _validationMessage;
}
set
{
_validationMessage = value;
RaisePropertyChanged(() => this.ValidationMessage);
}
}
#endregion
#region Commands
public ICommand LoginCommand
{
get
{
return _loginCommand ?? (_loginCommand =
new RelayCommand<object>((param) => ExecuteLoginCommand(param), (param) => CanExecuteLoginCommand(param)));
}
}
private bool CanExecuteLoginCommand(object parameter)
{
var paramArray = (object[])parameter;
if (paramArray == null) return false;
PasswordBox pb = paramArray[0] as PasswordBox;
if (pb == null) return false;
var pwdText = pb.Password;
return !(String.IsNullOrEmpty(pwdText) && Login != null);
}
private void ExecuteLoginCommand(object parameter)
{
Logger.InfoFormat("User [{0}] attempting to login", this.Login);
DisplayLoginButton = false;
DisplayLoginProgressRing = true;
EnableInput = false;
var paramArray = (object[])parameter;
var pb = paramArray[0] as PasswordBox;
var loginWindow = paramArray[1] as LoginView;
if (pb != null)
Password = pb.Password;
if (ValidateInput())
{
if (SynchronizationContext.Current == null)
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
var curSyncContext = SynchronizationContext.Current;
bool authenticated = false;
Task.Factory.StartNew(() =>
{
authenticated = CredentialService.Instance.Store(int.Parse(Login), Password);
Thread.Sleep(1000);
}).ContinueWith((task) =>
{
curSyncContext.Send((param) =>
{
if (authenticated)
{
Logger.InfoFormat("User [{0}] Authenticated Successfully, Logging In", this.Login);
var mainWindow = new MainWindow();
mainWindow.Show();
loginWindow.Close();
}
else
{
Logger.InfoFormat("User [{0}] Failed to Authenticate", this.Login);
DisplayValidationMessage = true;
ValidationMessage = INVALID_CREDENTIALS;
DisplayLoginButton = true;
DisplayLoginProgressRing = false;
EnableInput = true;
}
}, null);
});
}
else
{
Logger.InfoFormat("User [{0}] failed input validation", this.Login);
DisplayValidationMessage = true;
ValidationMessage = INVALID_INPUT;
DisplayLoginButton = true;
DisplayLoginProgressRing = false;
EnableInput = true;
}
}
#endregion
我是 WPF、线程和分离 UI 这个概念的新手。
所以这里我有一个设计良好的项目,其中所有计算都在一个方法内完成(例如 Command class 和 Execute 方法);用户界面包含多个用户控件。
由于计算需要几分钟,我想我应该使用 MainControl 用户控件 class.
上的进度条所以我在MainControl中创建了这个方法来更新进度条:
public void SetProgressBar(int Value, int Min = 0, int Max = 100)
{
if (Value <= Max && Min <= Value)
{
StatusProgress.Minimum = Min;
StatusProgress.Maximum = Max;
StatusProgress.Dispatcher.Invoke(
new Action(() => this.StatusProgress.Value = Value),
System.Windows.Threading.DispatcherPriority.Background);
}
}
然后我在 Command class:
中创建了对 MainControl 的引用private MainControl MainControlRef;
所以在我计算的不同阶段,我可以使用以下方式报告进度:
MainControlRef.SetProgressBar(10);
这是我能想到的。我认为这感觉不对。如果您能给我一些反馈,我将不胜感激。
此外,我注意到进度条有时会更新,有时不会。
使用 MVVM 模式很容易,您的 VM 通常会包含命令对象(研究 relay command)和视图所需的其他数据,例如保存进度条值的 int。 然后您的视图将绑定到此 VM,因此一旦您的命令正在执行并更新进度条值,您的视图也会更新
以下旧项目的示例,希望对您有所帮助
public class LoginViewModel : ViewModelBase
{
private static ILog Logger = LogManager.GetLogger(typeof(LoginViewModel));
#region Properties
private String _title;
private String _login;
private String _password;
private String _validationMessage;
private bool _displayLoginButton;
private bool _displayLoginProgressRing;
private bool _enableInput;
private bool _displayValidationMessage;
private ICommand _loginCommand;
public LoginViewModel()
{
DisplayLoginButton = EnableInput = true;
DisplayLoginProgressRing = DisplayValidationMessage = false;
}
public bool DisplayValidationMessage
{
get { return _displayValidationMessage; }
set
{
_displayValidationMessage = value;
RaisePropertyChanged(() => this.DisplayValidationMessage);
}
}
public bool DisplayLoginButton
{
get { return _displayLoginButton; }
set
{
_displayLoginButton = value;
RaisePropertyChanged(() => this.DisplayLoginButton);
}
}
public bool EnableInput
{
get { return _enableInput; }
set
{
_enableInput = value;
RaisePropertyChanged(() => this.EnableInput);
}
}
public bool DisplayLoginProgressRing
{
get { return _displayLoginProgressRing; }
set
{
_displayLoginProgressRing = value;
RaisePropertyChanged(() => this.DisplayLoginProgressRing);
}
}
public String Title
{
get
{
return _title;
}
set
{
_title = value;
RaisePropertyChanged(() => this.Title);
}
}
public String Login
{
get
{
return _login;
}
set
{
_login = value;
RaisePropertyChanged(() => this.Login);
}
}
public String Password
{
get
{
return _password;
}
set
{
_password = value;
RaisePropertyChanged(() => this.Password);
}
}
public String ValidationMessage
{
get
{
return _validationMessage;
}
set
{
_validationMessage = value;
RaisePropertyChanged(() => this.ValidationMessage);
}
}
#endregion
#region Commands
public ICommand LoginCommand
{
get
{
return _loginCommand ?? (_loginCommand =
new RelayCommand<object>((param) => ExecuteLoginCommand(param), (param) => CanExecuteLoginCommand(param)));
}
}
private bool CanExecuteLoginCommand(object parameter)
{
var paramArray = (object[])parameter;
if (paramArray == null) return false;
PasswordBox pb = paramArray[0] as PasswordBox;
if (pb == null) return false;
var pwdText = pb.Password;
return !(String.IsNullOrEmpty(pwdText) && Login != null);
}
private void ExecuteLoginCommand(object parameter)
{
Logger.InfoFormat("User [{0}] attempting to login", this.Login);
DisplayLoginButton = false;
DisplayLoginProgressRing = true;
EnableInput = false;
var paramArray = (object[])parameter;
var pb = paramArray[0] as PasswordBox;
var loginWindow = paramArray[1] as LoginView;
if (pb != null)
Password = pb.Password;
if (ValidateInput())
{
if (SynchronizationContext.Current == null)
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
var curSyncContext = SynchronizationContext.Current;
bool authenticated = false;
Task.Factory.StartNew(() =>
{
authenticated = CredentialService.Instance.Store(int.Parse(Login), Password);
Thread.Sleep(1000);
}).ContinueWith((task) =>
{
curSyncContext.Send((param) =>
{
if (authenticated)
{
Logger.InfoFormat("User [{0}] Authenticated Successfully, Logging In", this.Login);
var mainWindow = new MainWindow();
mainWindow.Show();
loginWindow.Close();
}
else
{
Logger.InfoFormat("User [{0}] Failed to Authenticate", this.Login);
DisplayValidationMessage = true;
ValidationMessage = INVALID_CREDENTIALS;
DisplayLoginButton = true;
DisplayLoginProgressRing = false;
EnableInput = true;
}
}, null);
});
}
else
{
Logger.InfoFormat("User [{0}] failed input validation", this.Login);
DisplayValidationMessage = true;
ValidationMessage = INVALID_INPUT;
DisplayLoginButton = true;
DisplayLoginProgressRing = false;
EnableInput = true;
}
}
#endregion