异步更新属性 c# MVVM



XAML 绑定到一个 ViewModelMainVM,该加载另外 2 个子 ViewModelsSubVM1SubVM2。我正在使用John Thiriet提供的异步命令。我的意图:使用在 MainVM 中定义的命令,使用 SubVM1 中的异步函数从 SubVM2 更新属性。 (XAML(

<Window.Resources>
<local:MainVM x:Key="main"/>
<local:SubVM2 x:Key="subvm2"/>
</Window.Resources>
<Grid>
<Label Content="{Binding MyValue}" DataContext="{StaticResource subvm2}" FontSize="40"/>
<Button Command="{Binding MyCommand}" DataContext="{StaticResource main}" Width="100" Height="100" Content="GO"/>
</Grid>

主虚拟机

class MainVM : VMBase
{
private SubVM1 _subvm1;
private SubVM2 _subvm2;
private bool _isBusy;
public SubVM1 Subvm1
{
get => _subvm1;
set
{ _subvm1 = value; OnPropertyChanged("Subvm1"); }
}
public SubVM2 Subvm2
{
get => _subvm2;
set
{ _subvm2 = value; OnPropertyChanged("Subvm2"); }
}
public bool IsBusy
{
get => _isBusy;
set
{ _isBusy = value; OnPropertyChanged("IsBusy"); }
}
public IAsyncCommand MyCommand { get; set; }
public MainVM()
{
Subvm1 = new SubVM1();
Subvm2 = new SubVM2();
MyCommand = new AsyncCommand(Increment, MuchBusiness);
}
private async Task Increment()
{
try
{
IsBusy = true;
await Subvm1.MyAsyncFunc(Subvm2.MyValue);
}
finally
{
IsBusy = false;
}
}
private bool MuchBusiness()
{
return !IsBusy;
}
}

子虚拟机1

class SubVM1 : VMBase
{
public async Task MyAsyncFunc(double MyValue)
{
await Task.Run(() =>
{
int i = 0;
while (i < 20)
{
MyValue = i;
i++;
Console.WriteLine(MyValue);
}
});
}
}

子VM2

class SubVM2 : VMBase
{
private double _myValue;
public double MyValue
{
get => _myValue;
set
{ _myValue = value; OnPropertyChanged("MyValue"); }
}
public SubVM2() { }
}

我尝试使用Stephen Cleary的这篇文章。这真的很有启发性,但我只明白我做错了。我似乎无法弄清楚如何使用他提供的代码。另外,我找不到通常真正帮助我理解的源代码。 我也读过调度程序,但同样,没有源代码 有这个解决方案旨在修改OnPropertyChanged,但是这是来自win8应用程序,我无法从那里推断。

详细的解决方案,以及获取与文章相关的文件的链接

我最终使用了MVVMLight。此库中的所有函数前面都带有GS

XAML

<Window.Resources>
<local:ViewModelLocator x:Key="Locator"/>
</Window.Resources>
<Grid DataContext="{Binding Main, Source={StaticResource Locator}}" >
<Label Content="{Binding SubVM2.MyValue}" FontSize="40"/>
<Button Command="{Binding SubVM1.OkCommand}" Width="100" Height="100" Content="GO"/>
</Grid>

主虚拟机

public class MainVM : VMBase
{
public SubVM1 SubVM1 { get; }
public SubVM2 SubVM2 { get; } = new SubVM2();
public MainVM()
{
SubVM1 = new SubVM1(SubVM2);
//Subvm2 = new SubVM2();
}
}

子VM1(使用 IsBusy 作为可以执行的参数(

using GS = GalaSoft.MvvmLight.Command;
[...]
public class SubVM1 : VMBase
{
private SubVM2 _subVM2 { get; set; }
private bool _isBusy;
public bool IsBusy
{
get => _isBusy;
set
{ _isBusy = value; OnPropertyChanged("IsBusy"); }
}
public SubVM1() { }
public SubVM1(SubVM2 SubVM2)
{
_subVM2 = SubVM2; ;
}

private GS.RelayCommand _okCommand;
public GS.RelayCommand OkCommand
{
get
{
return _okCommand
?? (_okCommand = new GS.RelayCommand(
async () =>
{
IsBusy = true;
Console.WriteLine(IsBusy);
await Task.Run(
() =>
{
// This is a background operation!
IsBusy = true;
_subVM2.MyValue = 0;
while (_subVM2.MyValue < 30)
{
_subVM2.MyValue++;
// Sleep for a while
Thread.Sleep(500);
}
});
IsBusy = false;
Console.WriteLine(IsBusy);
},()=> { return !IsBusy; },false));
}
}
}

子VM2

public class SubVM2 : VMBase {
private double _myValue;
public double MyValue
{
get => _myValue;
set
{ _myValue = value; OnPropertyChanged("MyValue"); }
}
public SubVM2() { } }

视图模型定位器

public class ViewModelLocator
{
/// <summary>
/// Initializes a new instance of the ViewModelLocator class.
/// </summary>
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
////if (ViewModelBase.IsInDesignModeStatic)
////{
////    // Create design time view services and models
////    SimpleIoc.Default.Register<IDataService, DesignDataService>();
////}
////else
////{
////    // Create run time view services and models
////    SimpleIoc.Default.Register<IDataService, DataService>();
////}
SimpleIoc.Default.Register<MainVM>();
}
public MainVM Main
{
get
{
return ServiceLocator.Current.GetInstance<MainVM>();
}
}
public static void Cleanup()
{
// TODO Clear the ViewModels
}
}

我不知道这个解决方案有多漂亮,所以我会等一会儿,然后再将其标记为答案。不过它为我做了工作!:)

最新更新