我是WPF的新手,现在我偶然发现了一些在互联网上找不到答案的东西。我有以下问题:
在同一个解决方案中,我有两个项目,一个是代表生产过程的应用程序,称为MaintenancePlanner,另一个是GUI,称为MaintenancePlannerGUI。
我想实现的目标如下:按下按钮后,生产过程的模拟开始(在MaintenancePlanner中进行)。然后,在MaintenancePlannerGUI中,我有一个进度条。进度条的值应根据MaintenancePlanner模拟中对象的属性值进行更改。
因此,我需要以某种方式绑定它。但是,我不知道如何做到这一点。我使用MVVM结构。因此,我的结构看起来如下:
- 维护计划员
- AssemblyFab.cs
- AssemblyLine.cs
- ShellModel.cs(类似于Program.cs,但仅专门用于维护计划器GUI)
- 维护计划器GUI
- 查看次数
- ShellViewModel.cs
- 检视模型
- ShellView.xaml
现在,例如AssemblyLine包含属性Speed
。请注意,AssemblyLine的多个示例以List<AssemblyLine> AssemblyLines
的形式附加到AssemblyFab。
在ShellView.xaml中,我有一个进度条:
<ProgressBar Width="10" Height="45" Margin="0,5,10,0" Orientation="Vertical" Minimum="0" Maximum="50" Value="{Binding ???}"/>
在ShellViewModel.cs中,我创建了MaintenancePlanner模拟AssemblyFabSim
的示例,方法是从MaintenancePlanner创建ShellModel.cs的示例,在MaintenancePlanner中创建了整个AssemblyFab及其组件,如下所示:
AssemblyFabSim = new ShellModel();
现在,我尝试了一些非常粗糙的东西,比如:
Value="{Binding AssemblyFabSim.AssemblyFab.AssemblyLines[0].Speed}
但这显然不起作用。我想到的另一个想法是使用NotifyPropertyChanged方法。
因此,在这种情况下,我可以在ShellViewModel.cs中创建一个名为test
的属性,并将其绑定到我的进度条。然后,如果ShellModel.cs中的属性发生更改,我可以通过获取通知来更新测试。但是,我还需要从ShellModel.cs中监视AssemblyFab和AssemblyLine中的更改。因此要将更改从AssemblyLine传播到AssemblyFab再传播到ShellModel再传播到ShellViewModel,然后再传播到视图。
private void ShellModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Speed")
{
test = AssemblyFabSim.AssemblyFab.AssemblyLines[0].MouldCleanInterval;
}
}
我想知道这是否确实是要走的路,如果是的话,究竟如何做到这一点?或者也许有其他更简单的方法?提前感谢!
编辑1
我的ShellViewModel.cs现在包含以下内容,因为ShellViewModel继承了INotifyPropertyChanged类,如下所示ShellViewModel : INotifyPropertyChanged
public ShellModel AssemblyFabSim { get; set; }
AssemblyFabSim.PropertyChanged += ShellModel_PropertyChanged;
private void ShellModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "TestSpeed")
{
test = AssemblyFabSim.AssemblyFab.AssemblyLines[0].Speed;
}
}
private double _test;
public double test
{
get { return _test; }
set
{
_test = value;
NotifyOfPropertyChange();
}
}
现在我绑定了我的进度条值,比如Value="{Binding test}
。然后ShellModel.cs也将继承INotifyPropertyChanged
,我添加:
public void UpdateSpeed()
{
try
{
TestSpeed = AssemblyFab.AssemblyLines[0].Speed;
}
catch (Exception e)
{
throw new Exception(e.Message);
}
NotifyOfPropertyChange(nameof(TestSpeed));
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyOfPropertyChange([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
从汇编行中调用**UpdateSpeed()**方法。
新问题:进程栏的值被更新,但只有在模拟完成后我才能看到结果。也就是说,GUI只是冻结,直到模拟停止,然后它显示速度的最后一个值。
2条答案
按热度按时间iaqfqrcu1#
如果您的shellViewModel具有类似以下的属性
您应该能够绑定到它,并且如果路径中的所有其他属性都正确,它们也应该可以工作。但据我所知,绑定不支持索引器,所以我认为
AssemblyLines[0]
将无法工作。Wpf并不关心类在什么项目中定义,只关心它有一个要绑定的对象,并且属性的命名正确。通常一切都还应该实现
INotifyPropertyChanged
才能很好地工作。但是请注意,深度嵌套的路径可能不是一个好主意,您应该尝试将UI和业务逻辑分开,因此您应该尝试避免绑定到除为它设计的viewModel类之外的任何东西。
值得注意的是,如果你有一个进度条,你应该绑定到一个
Progress<T>
对象,该对象被传递给需要报告进度的方法。你应该避免在执行工作的对象上使用progress-property,毕竟,如果从多个线程并发调用该方法会发生什么?6g8kf2rb2#
您需要确保在后台线程上调用
UpdateSpeed()
,因为UI线程无法同时更新进度栏和执行代码。