I want to change the background of a WPF Window from another thread, after a delay (Thread.Sleep()
in the code tries to mimic an I/O operation). The action will be invoked when a button is pressed.
More specifically, when the button is clicked I want to
- The button to disabled
- The color of the background changed after a delay of seconds
- The button to be enabled again
When I run the application and fire the event I cannot see the button disabled. The background change does happen though, and I'm guessing it has to do with the UI thread and the Dispatcher
. But I've also tried to disable it like this
MyButton.Dispatcher.Invoke(() => MyButton.IsEnabled = false)
without any success.
Is anyone able to explain why this is happening and how can I solve it?
XAML
<Window x:Class="ThreadingModel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ThreadingModel"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<StackPanel x:Name='Parent' Background='Green'>
<TextBlock HorizontalAlignment='Center'
Margin='10'
FontSize='32'>Threading and UI</TextBlock>
<TextBlock Margin='10'
FontSize='22'
TextWrapping='Wrap'>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</TextBlock>
<Button Content='Change Color'
Width='150'
Height='50'
Margin='10'
FontSize='22'
Click='Button_Click'
x:Name='MyButton'/>
</StackPanel>
</Window>
Code (C#)
public partial class MainWindow : Window
{
private delegate void OneArgumentDelegate(int arg);
private bool isGreen = true;
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//MyButton.IsEnabled = false;
MyButton.Dispatcher.Invoke(() => MyButton.IsEnabled = false);
/* This starts a background thread from the pool, right?*/
MyButton.Dispatcher.BeginInvoke(new OneArgumentDelegate(Change_Background_After), DispatcherPriority.Normal, 3000);
}
private void Change_Background_After(int delay)
{
Thread.Sleep(delay);
if (isGreen)
{
Parent.Background = Brushes.Red;
isGreen = false;
}
else
{
Parent.Background = Brushes.Green;
}
MyButton.IsEnabled = true;
}
}