Search code examples
wpfstatusbar

StatusBar Text/Background updates don't work reliably


New to WPF, trying to figure out why my style changes for a StatusBar aren't working reliably. Code seems very straightforward:

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;
        }
    }

Can somebody show me the error in my ways?

The relevant 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>

Update: Thanks to these suggestions, I've been able to get the yellow text to work by doing the below. Still no luck with the green Success message. I got a whole bunch of reading on async to do to fully understand the execution flow and what the suggestions fully mean (last time I did anything like this, BackgroundWorkers were all the rage). I appreciate any other hints/explanations.

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);
    }

Solution

  • In a single-threaded application, updates to controls are not going to have an effect until your event handler is done and the screen can be updated. Your Thread.Sleep(2000); blocks up the whole UI.

    Make the method async and replace the sleep with await Task.Delay( 2000 ). This will allow the normal event loop to take over during those two seconds and the UI will get updated.

    Edit: Your "Connecting" and yellow background still aren't going to work because (I assume) m_Manager.P4Login() is a synchronous function. If you can't make it async, do this right before calling it:

    await Dispatcher.Yield( DispatcherPriority.ApplicationIdle );
    

    This lets the event loop briefly take over and process all outstanding events (including your text and background color update) before your code continues.