我正在努力学习WPF并试图找出最佳做法。我了解基本的教程,但它们通常不会涵盖更多的“复杂”行为。
我的用例如下:用户输入许可证密钥,然后单击“确定”按钮。在后台,我必须异步调用一个Web API,该API将返回一个对象(LicenseCheckResult),其中包含有关所提供许可证的详细信息(到期,类型,...)。如果许可证密钥有效,则将其存储。然后相应地更新UI(与许可证相关的用户控件的显示根据LicenseCheckResult对象而改变)。
由于检查许可证的调用是异步的,因此我使用了此处描述的IAsyncCommand(https://docs.microsoft.com/en-us/archive/msdn-magazine/2014/april/async-programming-patterns-for-asynchronous-mvvm-applications-commands)
这是代码,在我的MainWindowViewModel中,我有:
public IAsyncCommand _checkLicenseCommand;
public IAsyncCommand CheckLicenseCommand { get; private set; }
public async Task<LicenseCheckResult> CheckLicense(CancellationToken token)
{
var task = await _licenseCheckProvider.CheckLicenseAsync(_generalSettings.ID, LicenseKey, token);
if (task.Status == LicenseStatus.Valid.ToString())
{
_generalSettings.LicenseKey = _encryptionProvider.Encrypt(LicenseKey); // Store license key
SettingLicense = false; // toggle the license key input modal dialog
}
return task;
}
public MainWindowViewModel(IOptions<GeneralSettings> generalSettings, IEncryptionProvider encryptionProvider, ILicenseCheckProvider licenseCheckProvider)
{
_generalSettings = generalSettings.Value;
_licenseCheckProvider = licenseCheckProvider;
_encryptionProvider = encryptionProvider;
CheckLicenseCommand = AsyncCommand.Create(token => CheckLicense(token));
... other stuff
}
[CheckLicenseCommand已绑定到“确定”按钮。
在主窗口XAML中,LicensingUserControl的可见性绑定到IAsyncCommand的任务
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Vertical" Visibility="{Binding CheckLicenseCommand.Execution, Converter={StaticResource NullToVisibilityConverter}}">
<localControls:LicensingUserControl HorizontalAlignment="Stretch" VerticalAlignment="Top" Visibility="{Binding CheckLicenseCommand.Execution.IsSuccessfullyCompleted, Converter={StaticResource boolTovisibility}}" />
</StackPanel>
... other stuff
</StackPanel>
在LicensingUserControl中,显示绑定到IAsyncCommand返回的任务的结果:
<Grid x:Name="LayoutRoot" Background="{Binding CheckLicenseCommand.Execution.Result.Background}">
<StackPanel x:Name="MainStackPanel" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" >
<TextBlock Text="Type:" Width="Auto" VerticalAlignment="Center" TextAlignment="Right" FontWeight="Bold" Margin="0"/>
<Label Content="{Binding CheckLicenseCommand.Execution.Result.Type}" VerticalAlignment="Center" Width="Auto" Margin="0"/>
<TextBlock Text="License:" Width="Auto" VerticalAlignment="Center" TextAlignment="Right" FontWeight="Bold" Margin="0"/>
<Label Content="{Binding CheckLicenseCommand.Execution.Result.Status}" VerticalAlignment="Center" Width="Auto" Margin="0"/>
... other stuff
这可以运行,但是CheckLicense方法可以吗? (我正在等待此方法中的任务,以便能够使用异步调用的结果,然后将任务返回给UI以进行更新。)如果没有,那么这样做的正确方法是什么?
此外,我是否应该研究一种框架来帮助更复杂的行为(我正在使用.Net Core?
您使用非常复杂的行为,我认为您的方法有误。但是,如果我想回答您的问题,只需继承MainWindowViewModel中的INotifyPropertyChanged接口,然后在CheckLicenseCommand的CheckLicense中调用OnPropertyChanged:
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public async Task<LicenseCheckResult> CheckLicense(CancellationToken token)
{
var task = await _licenseCheckProvider.CheckLicenseAsync(_generalSettings.ID, LicenseKey, token);
if (task.Status == LicenseStatus.Valid.ToString())
{
_generalSettings.LicenseKey = _encryptionProvider.Encrypt(LicenseKey); // Store license key
SettingLicense = false; // toggle the license key input modal dialog
}
OnPropertyChanged(nameof(CheckLicenseCommand));
return task;
}