7

我正在尝试在 WPF 中对 ProgressBar 的 value 属性进行数据绑定。我设置了一个按钮来增加 ProgressBar 的值的数据绑定 int 属性。当我按下按钮时,它应该使 ProgressBar 的值从 1 增加到 100。但是......它似乎没有工作,我不确定我做错了什么。这是我的 XAML ......

<Window x:Class="ProgressBarExample2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="250" Width="400" Background="WhiteSmoke">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
    <Button Name="goButton" Height="30" Width="50" Margin="0,10,0,50" Click="goButton_Click">GO!</Button>
    <ProgressBar Name="progressBar" Width="300" Height="30" Value="{Binding Percent, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>

这是我背后的代码...

public partial class MainWindow : Window, INotifyPropertyChanged
{
    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChange(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion

    private int percent = 0;
    public int Percent
    {
        get { return this.percent; }
        set 
        {
            this.percent = value;
            NotifyPropertyChange("Percent");
        }
    }

    public MainWindow()
    {
        InitializeComponent();
    }


    private void goButton_Click(object sender, RoutedEventArgs e)
    {
        for (Percent = 0; Percent <= 100; Percent++)
        {
            Thread.Sleep(50);
        }
    }
}
4

3 回答 3

7

Thread.Sleep 正在阻塞 UI 线程并停止进度条的动画。

您可以使用以下命令暂停执行而不阻塞 UI 线程。将您的Thread.Sleep(50)电话替换为Wait(50)

/// <summary>
/// Stop execution for a specific amount of time without blocking the UI
/// </summary>
/// <param name="interval">The time to wait in milliseconds</param>
public static void Wait(int interval)
{
    ExecuteWait(() => Thread.Sleep(interval));
}

public static void ExecuteWait(Action action)
{
    var waitFrame = new DispatcherFrame();

    // Use callback to "pop" dispatcher frame
    IAsyncResult op = action.BeginInvoke(dummy => waitFrame.Continue = false, null);

    // this method will block here but window messages are pumped
    Dispatcher.PushFrame(waitFrame);

    // this method may throw if the action threw. caller's responsibility to handle.
    action.EndInvoke(op);
}
于 2013-01-10T16:24:43.960 回答
1

没有设置窗口(或 StackPanel)的 DataContext 的代码(已发布)。

要确定原因,请查看输出窗口中的绑定错误。


此外,

private void goButton_Click(object sender, RoutedEventArgs e)
{
    for (Percent = 0; Percent <= 100; Percent++)
    {
        Thread.Sleep(50);
    }
 }

这会阻止消息处理,因此您的应用将在 5 秒内“无响应”。不会进行任何输入处理和屏幕更新。繁忙的循环在事件驱动的 GUI 中根本就不好。

将此代码移至 Backgroundworker 或使用 Timer。

于 2013-01-10T16:15:40.670 回答
1

还有其他没有数据绑定的解决方案。你可以声明一个委托

private delegate void UpdateProgressBarDelegate(System.Windows.DependencyProperty dp, Object value);

并在按钮的点击事件中使用

private void goButton_Click(object sender, RoutedEventArgs e)
        {
             //Configure the ProgressBar
            progressBar.Minimum = 0;
            progressBar.Maximum = 100;
            progressBar.Value = 0;

            //Stores the value of the ProgressBar
            double value = 0;

            //Create a new instance of our ProgressBar Delegate that points
            //  to the ProgressBar's SetValue method.
            UpdateProgressBarDelegate updatePbDelegate = new UpdateProgressBarDelegate(progressBar.SetValue);

            //Tight Loop:  Loop until the ProgressBar.Value reaches the max
            do
            {
                value += 1;

                /*Update the Value of the ProgressBar:
                  1)  Pass the "updatePbDelegate" delegate that points to the ProgressBar1.SetValue method
                  2)  Set the DispatcherPriority to "Background"
                  3)  Pass an Object() Array containing the property to update (ProgressBar.ValueProperty) and the new value */
                Dispatcher.Invoke(updatePbDelegate,
                    System.Windows.Threading.DispatcherPriority.Background,
                    new object[] { ProgressBar.ValueProperty, value });

            }
            while (progressBar.Value != progressBar.Maximum);
        }
于 2013-01-10T16:34:35.313 回答