绑定值的问题

Problems with binding values

我在将值绑定到控件时遇到问题。我检查了我拥有的其他 windows,我认为我正在以同样的方式进行操作。 我想在 main window 打开之前显示类似从 App 加载 window 的内容。问题是什么都没有改变(text/content/value 个控件)。

初始化窗口:

public InitializationWindow()
{
    ...
    InitializationWindowClass.Progress = new InitializationWindowClass();
    this.mainSP.DataContext = InitializationWindowClass.Progress;
}

和xaml的一部分:

<StackPanel Name="mainSP" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="0, 0, 0, 10">
    <TextBlock x:Name="tblProgress" FontSize="14" Text="{Binding ProgressText}" TextAlignment="Center" TextWrapping="Wrap" />
    <Grid>
            <telerik:RadProgressBar x:Name="progress" Value="{Binding ProgressValue}" telerik:StyleManager.Theme="Summer" Height="25" IsIndeterminate="False" />
            <Label x:Name="lblPercent" FontWeight="Bold" Content="{Binding ProgressValueString}" HorizontalAlignment="Center" VerticalContentAlignment="Center" />
    </Grid>
</StackPanel>

初始化窗口类:

public class InitializationWindowClass : INotifyPropertyChanged
{
    public static InitializationWindowClass Progress { get; set; }
    private string progressText = String.Empty, progressValueString = String.Empty;
    private int progressValue = 0;
    public event PropertyChangedEventHandler PropertyChanged;

    public string ProgressText
    {
        get
        {
            return progressText;
        }
        set
        {
            progressText = value;
            NotifyPropertyChanged("ProgressText");
        }
    }

    public string ProgressValueString
    {
        get
        {
            return progressValueString;
        }
        set
        {
            progressValueString = value;
            NotifyPropertyChanged("ProgressValueString");
        }
    }

    public int ProgressValue
    {
        get
        {
            return progressValue;
        }
        set
        {
            progressValue = value;
            ProgressValueString = String.Format("{0}%", progressValue);
            NotifyPropertyChanged("ProgressValue");
            NotifyPropertyChanged("ProgressValueString");
        }
    }

    private void NotifyPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

和App.xaml.cs的一部分:

protected override void OnStartup(StartupEventArgs e)
{
    InitializationWindow iw = new InitializationWindow(); 
    iw.Show();
    InitializationWindowClass.Progress.ProgressValue = Convert.ToInt32(((decimal)count / (decimal)sum) * 100);
    InitializationWindowClass.Progress.ProgressText = "Some text";
    ...
    ...
    InitializationWindowClass.Progress.ProgressValue = Convert.ToInt32(((decimal)count / (decimal)sum) * 100);
    InitializationWindowClass.Progress.ProgressText = "New text";
    ...
    ...
}

我检查过,当我更改时,即 ProgressValue 从 App.xaml.cs,该值正在更改 - 将变为

get
{
    return progressValue;
}

所以问题是 - 我做错了什么?

这是线程问题。绑定更改发布到 Dispatcher,然后 UI 线程将这些事件从 Dispatcher 队列中拉出并处理它们。

此处您正在更改 OnStartup 事件中的绑定,该事件本身由 UI 线程处理。这意味着在退出 OnStartup 事件之前不会处理这些绑定更改。您最终在用户界面中看到的可能只是这些进度属性上次更改时的值。

您需要做的是将进度报告移至另一个线程。换句话说,使用 async/await 或其他一些线程机制,将 OnStartup 事件中当前完成的工作转移到另一个线程。


原文错误答案如下:

ProgressTextProgressValueStringProgressValue 都是 InitializationWindowClass 上的属性,而不是 InitializationWindow。看起来您需要将 StackPanel 上的 DataContext 设置为指向 InitializationWindowProgress 属性,或者包括 Progress 属性 作为单个元素的绑定路径的一部分。

也就是说,要么这样:

<StackPanel ... DataContext="{Binding Progress}">
    ... rest the same ...
</StackPanel>

或者这个:

<StackPanel ...>
    <TextBlock ... Text="{Binding Progress.ProgressText}" ... />
    <Grid>
        <telerik:RadProgressBar ... Value="{Binding Progress.ProgressValue}" ... />
        <Label ... Content="{Binding Progress.ProgressValueString}" ... />
    </Grid>
</StackPanel>

你所做的是行不通的。您正在显示启动画面并在同一线程上执行加载操作。这样,当您的加载操作 运行 时,主 UI 线程很忙并且没有更新,即使后台数据正在正确更改也是如此。这就是为什么您可能会看到 "wait" 光标,启动画面 window 没有响应,并且您的主 window 甚至可能根本不会出现。

  • SplashScreen 应该在不同的线程上显示
  • 您必须有一种与该线程通信的方式,因为:
  • 您不能使用另一个线程从一个线程直接更新 UI

Here 你有一个很好的在 wpf 中使用 SplashScreen 的例子