【问题标题】:StatusBar Text/Background updates don't work reliably状态栏文本/背景更新不能可靠地工作
【发布时间】:2017-01-04 20:15:47
【问题描述】:

WPF 新手,试图弄清楚为什么我对 StatusBar 的样式更改不能可靠地工作。代码看起来很简单:

private void OnTryP4Login(object sender, RoutedEventArgs e)
    {
        statusText.Text = string.Format("Connecting to {0} as '{1}'.",
                                         textBoxUri.Text, textBoxUser.Text); // <-- Doesn't work
        statusBar.Background = Brushes.Yellow; // <-- Doesn't work

        if (m_Manager.P4Login(textBoxUri.Text, textBoxUser.Text,
            textBoxClientSpec.Text, passwordBox.Password))
        {
            statusText.Text = "SUCCESS!"; // <-- Doesn't work
            statusBar.Background = Brushes.Green; // <-- Doesn't work
            Thread.Sleep(2000);
            this.Close();
        }
        else
        {
            statusBar.Background = Brushes.Red; // <-- THIS works
            statusText.Text = "Error connecting to Perforce server!"; // <-- THIS works
            buttonConnect.Visibility = Visibility.Collapsed;
            buttonOK.Visibility = Visibility.Visible;
        }
    }

谁能以我的方式告诉我错误?

相关的 XAML:

<Window x:Class="WpfClient.P4LoginDialog"
    [...]
    Icon="feat.ico">
<DockPanel>
    <Grid DockPanel.Dock="Top" Height="158">
    [...]
    <Button x:Name="buttonConnect" Content="Connect" Click="OnTryP4Login" HorizontalAlignment="Left" Margin="274,130,0,-18" VerticalAlignment="Top" Width="75"/>

    </Grid>
    <StatusBar x:Name="statusBar" Height="25" Background="#888" DockPanel.Dock="Bottom" HorizontalAlignment="Stretch" >
        <TextBlock x:Name="statusText"
                Width="Auto" 
                Height="Auto" 
                Foreground="#fff" 
                Text="Connect to P4 for live integration" 
                HorizontalAlignment="Right"
                TextAlignment="Right"
                />
    </StatusBar>
</DockPanel>

更新:多亏了这些建议,我已经能够通过执行以下操作使黄色文本正常工作。绿色成功消息仍然没有运气。为了完全理解执行流程和建议的全部含义,我阅读了大量关于 async 的内容(上次我做这样的事情时,BackgroundWorkers 风靡一时)。我感谢任何其他提示/解释。

private async void OnTryP4Login(object sender, RoutedEventArgs e)
    {
        statusText.Text = string.Format("Connecting to {0} as '{1}'.",
                          textBoxUri.Text, textBoxUser.Text); // <-- Works now
        statusBar.Background = Brushes.DarkGoldenrod; // <-- Works now

        Task<bool> getConnection = m_Manager.P4Login(textBoxUri.Text, textBoxUser.Text, textBoxClientSpec.Text, passwordBox.Password);
        bool connection = await getConnection;

        if (connection)
        {
            statusText.Text = "SUCCESS!"; // <-- Still doesn't work (stays DarkGoldenrod)
            statusBar.Background = Brushes.Green; // <-- Still doesn't work (stays DarkGoldenrod)
            Thread.Sleep(2000);
            this.Close();
        }
        else
        {
            statusBar.Background = Brushes.Red; // <-- Still works
            statusText.Text = "Error connecting to Perforce server!"; // <-- Still works
            buttonConnect.Visibility = Visibility.Collapsed;
            buttonOK.Visibility = Visibility.Visible;
        }
    }

public async Task<bool> P4Login(string uri, string user, string clientSpec, string password)
    {
        await Task.Delay(100);
        return m_PI.Connect(uri, user, clientSpec, password);
    }

【问题讨论】:

  • 你在哪里附加事件处理程序OnTryP4Login
  • 您的代码如何知道何时需要触发 OnTryP4Login 事件?
  • 添加到主帖: 代码肯定会触发,有时(在连接失败时)会正确到达 Else {} 语句。
  • 可能P4Login方法返回的太快了,你看不到黄色?
  • 我到处都有 Thread.Sleep() 以确保事情不会进展得太快。您还将在上面的代码中看到 2 秒的等待,在此期间绿色状态栏应该可见。

标签: wpf statusbar


【解决方案1】:

在单线程应用程序中,在事件处理程序完成并且屏幕可以更新之前,对控件的更新不会生效。您的 Thread.Sleep(2000); 会阻塞整个 UI。

创建方法async 并将sleep 替换为await Task.Delay( 2000 )。这将允许正常的事件循环在这两秒钟内接管,并且 UI 将得到更新。

编辑:您的“正在连接”和黄色背景仍然无法正常工作,因为(我假设)m_Manager.P4Login() 是一个同步函数。如果您无法使其异步,请在调用它之前执行此操作:

await Dispatcher.Yield( DispatcherPriority.ApplicationIdle );

这让事件循环在您的代码继续之前短暂接管并处理所有未完成的事件(包括您的文本和背景颜色更新)。

【讨论】:

    【解决方案2】:

    我认为整个代码在 GUI 线程中运行并阻止 WPF 更新 GUI。

    试试这个:

    private async void OnTryP4Login(object sender, RoutedEventArgs e)
    {
        statusText.Text = string.Format("Connecting to {0} as '{1}'.",
                                         textBoxUri.Text, textBoxUser.Text); // <-- Doesn't work
        statusBar.Background = Brushes.Yellow; // <-- Doesn't work
    
        await Task.Delay(100);
    
        if (m_Manager.P4Login(textBoxUri.Text, textBoxUser.Text,
            textBoxClientSpec.Text, passwordBox.Password))
        {
            statusText.Text = "SUCCESS!"; // <-- Doesn't work
            statusBar.Background = Brushes.Green; // <-- Doesn't work
            Thread.Sleep(2000);
            this.Close();
        }
        else
        {
            statusBar.Background = Brushes.Red; // <-- THIS works
            statusText.Text = "Error connecting to Perforce server!"; // <-- THIS works
            buttonConnect.Visibility = Visibility.Collapsed;
            buttonOK.Visibility = Visibility.Visible;
        }
    }
    

    如果可行,您可能应该像这样运行实际的登录异步:

    var loginSucceeded = await Task.Run(() => m_Manager.P4Login(textBoxUri.Text, textBoxUser.Text,
            textBoxClientSpec.Text, passwordBox.Password));
    

    而不是使用Task.Delay(100)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-26
      • 2016-11-30
      • 1970-01-01
      • 1970-01-01
      • 2019-08-09
      • 1970-01-01
      • 2019-11-20
      相关资源
      最近更新 更多