Welcome to StackOverflow !
Since your code is synchronous it is blocking, hence the behavior you get. There is also the need to consider using the Dispatcher
but luckily in your case you haven't encountered such issue.
Suggestions:
- use a ViewModel
- bind to some properties in it to enable/disable your UI
- doing so separates concerns and simplifies your thing in general
Example : a 5 second work that disables the UI (really simple !)

Points of interest in my code:
- by putting all controls that must be disabled within a
StackPanel
and binding its IsEnabled
property the model's IsAvailable
property I effectively simplify this process
- no controls are modified from code-behind
- the view (your window) does nothing more than presenting, all your logic is in a model that is not tied to your window and can be reused somewhere else
XAML:
<Window x:Class="WpfApplication1.MainView"
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:wpfApplication1="clr-namespace:WpfApplication1"
Title="MainView"
Width="525"
Height="350"
d:DataContext="{d:DesignInstance wpfApplication1:MainViewModel,
d:IsDesignTimeCreatable=True}"
mc:Ignorable="d">
<Grid>
<StackPanel>
<Button Command="{Binding DoSomeWork}" Content="Do some long work" />
<StackPanel IsEnabled="{Binding IsAvailable}">
<CheckBox Content="Test control 1" />
<RadioButton Content="Test control 2" />
</StackPanel>
<TextBlock Text="Overall progress:" />
<ProgressBar Height="10" Value="{Binding CurrentProgress}" />
</StackPanel>
</Grid>
</Window>
Code-behind:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
// put classes shown below here
}
Your model :
internal class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
// set-up environment
DoSomeWork = new DelegateCommand(DoSomeWorkExecute, DoSomeWorkCanExecute);
IsAvailable = true;
}
public int CurrentProgress
{
get { return _currentProgress; }
set
{
_currentProgress = value;
OnPropertyChanged();
}
}
#region IsAvailable
private bool _isAvailable;
private int _currentProgress;
public bool IsAvailable
{
get { return _isAvailable; }
set
{
_isAvailable = value;
OnPropertyChanged();
}
}
#endregion
#region DoSomeWork
public DelegateCommand DoSomeWork { get; private set; }
private bool DoSomeWorkCanExecute(object arg)
{
return true;
}
private async void DoSomeWorkExecute(object o)
{
await Task.Run(() =>
{
IsAvailable = false;
var steps = 20;
var time = 5000;
var length = time/steps;
for (var i = 0; i < steps; i++)
{
Thread.Sleep(length);
var currentProgress = (int) (((((double) i + 1)*length)/time)*100);
CurrentProgress = currentProgress;
}
IsAvailable = true;
});
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
And a trivial command base for DoSomeWork
:
internal class DelegateCommand : ICommand
{
private readonly Func<object, bool> _canExecute;
private readonly Action<object> _execute;
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public DelegateCommand(Action<object> execute)
: this(execute, s => true)
{
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged;
}
TODO
Get familiar with:
You will experience some pain with these concepts the first time, but over time you will find these are the way to go esp. with WPF.
If you are satisfied with my answer, mark it as the answer, otherwise if you need some clarification then add a comment below and either me or someone will try to help further.