WPF ProgressBar没有更新

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完成其循环,然后突然进度条显示完整进度,即完成.

V.L*_*eon 0

发生这种情况是因为StatusBarItem默认样式将其设置HorizontalContentAlignmentLeft,这导致ProgressBar只能获得少量的水平空间。

您可以通过将's设置为 来使 完全ProgressBar填充,也可以设置的。StatusBarItemStatusBarItemHorizontalContentAlignmentStretchWidthProgressBar