Pro*_*ofK 5 wpf events user-interface mvvm progress-bar
这是随意的原型代码,因此我尝试了我认为应该工作的东西,如果没有,则在谷歌上搜索,然后在仔细阅读类似的问题之后再问这里.
我认为我有以下标记Shell:
<StatusBarItem Grid.Column="0">
<TextBlock Text="{Binding StatusMessage}" />
</StatusBarItem>
<Separator Grid.Column="1" />
<StatusBarItem Grid.Column="2">
<ProgressBar Value="{Binding StatusProgress}" Minimum="0" Maximum="100" Height="16" Width="198" />
</StatusBarItem>
Run Code Online (Sandbox Code Playgroud)
然后在ShellViewModel我有以下两个属性和一个事件处理程序:
private string _statusMessage;
public string StatusMessage
{
get => _statusMessage;
set => SetProperty(ref _statusMessage, value);
}
private double _statusProgress;
public double StatusProgress
{
get => _statusProgress;
set => SetProperty(ref _statusProgress, value);
}
private void OnFileTransferStatusChanged(object sender, FileTransferStatusEventArgs fileTransferStatusEventArgs)
{
StatusMessage = fileTransferStatusEventArgs.RelativePath;
StatusProgress = fileTransferStatusEventArgs.Progress;
}
Run Code Online (Sandbox Code Playgroud)
从文件下载助手类定期引发事件,即每n次迭代.
现在奇怪的是,当事件处理程序更新vm属性时,在Shell视图上,TextBlock绑定到StatusMessage更新并正确显示,但ProgressBar绑定到StatusProgress没有,并保持空白.如果我在事件处理程序中放置一个断点,我可以看到StatusProgress属性正在以0到100的各种值正确更新,但这并没有反映在ProgressBar.
事件处理程序在另一个线程上执行的想法(通常会导致UI更新问题)发生在我身上,但为什么一个UI元素正确更新而另一个没有?
注:我一直身世愚蠢的,而不是测试的ProgressBar静态,即刚刚设置的视图模型的StatusProgress一个值,并得到shell窗口来显示,而不需要通过下载循环下去.如果我这样做,进度条会显示一个或多或少与其Value属性对应的长度.在评论或答案中提出的布局更改建议都不会改变这一点.静态地,它始终可见并始终显示值.
示例:我创建了一个相信重复问题的小示例.在示例中,进度条在等待任务完成之前不会更新,我相信这是我的主要问题的情况,但这是一个很长的下载,我没有等到它完成之后才注意到进度条没有更新.
这是StatusBar`MainWindow.xaml:
<StatusBar DockPanel.Dock="Bottom" Height="20">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="2">
<ProgressBar Value="{Binding StatusProgress}" Maximum="100" Minimum="0" Height="16" Width="198" />
</StatusBarItem>
</StatusBar>
Run Code Online (Sandbox Code Playgroud)
随后的代码MainWindow.xaml.cs:
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
public MainWindowViewModel ViewModel => (MainWindowViewModel)DataContext;
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ViewModel.Download();
}
Run Code Online (Sandbox Code Playgroud)
而代码在MainWindowViewModel:
private string _statusMessage = "Downloading something";
public string StatusMessage
{
get => _statusMessage;
set
{
if (value == _statusMessage) return;
_statusMessage = value;
OnPropertyChanged();
}
}
private int _statusProgress;
public int StatusProgress
{
get => _statusProgress;
set
{
if (value == _statusProgress) return;
_statusProgress = value;
OnPropertyChanged();
}
}
public void Download()
{
var dl = new FileDownloader();
dl.ProgressChanged += (sender, args) =>
{
StatusProgress = args.Progress;
};
dl.Download();
}
Run Code Online (Sandbox Code Playgroud)
最后代码为FileDownloader:
public class ProgressChangedEventArgs
{
public int Progress { get; set; }
}
public class FileDownloader
{
public event EventHandler<ProgressChangedEventArgs> ProgressChanged;
public void Download()
{
for (var i = 0; i < 100; i++)
{
ProgressChanged?.Invoke(this, new ProgressChangedEventArgs{Progress = i});
Thread.Sleep(200);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在该示例中,进度条保持空白,直到FileDownloader完成其循环,然后突然进度条显示完整进度,即完成.
发生这种情况是因为StatusBarItem默认样式将其设置HorizontalContentAlignment为Left,这导致ProgressBar只能获得少量的水平空间。
您可以通过将's设置为 来使 完全ProgressBar填充,也可以设置的。StatusBarItemStatusBarItemHorizontalContentAlignmentStretchWidthProgressBar