Добро пожаловать в StackOverflow!
Поскольку ваш код является синхронным, он блокирует, следовательно, поведение вы получаете. Также необходимо рассмотреть возможность использования Dispatcher
, но, к счастью, в вашем случае вы не столкнулись с такой проблемой.
Предложения:
- Используйте ViewModel
- связывают с некоторыми свойствами в нем, чтобы включить/отключить интерфейс
- этом разделяет озабоченность и упрощает вашу вещь в общем
Пример: 5-секундная работа, которая отключает интерфейс (очень просто!)
Достопримечательности в моем коде:
- , поставив все элементы управления, которые должны быть отключены в
StackPanel
и связывания его IsEnabled
свойства в модели IsAvailable
свойство я эффективно упростить этот процесс
- никакие элементы управления не изменены с кода
- вид (ваше окно) ничего не делает больше, чем представление, вся ваша логика в модели, которая не привязана к вашему окну и могут быть повторно использованы в другом месте
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-за:
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
}
Ваша модель:
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
}
И тривиальная команда база для 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
Разберитесь с:
Вы будете испытывать некоторую боль с этими понятиями первый раз, но со временем вы обнаружите, что это способ пойти esp. с WPF.
Если вы удовлетворены моим ответом, отметьте его как ответ, иначе, если вам нужно уточнение, добавьте комментарий ниже, и либо я, либо кто-то попытается помочь дальше.
Если прослушивание занимает время, так как весь код, который вы использовали, обрабатывается одним и тем же потоком, то, что вы испытываете, является нормальным. Чтобы решить эту проблему, вам, вероятно, нужно сделать это многопоточным способом. Должен быть отдельный поток, который контролирует обработку пользовательского интерфейса, например, обновляет его состояние просмотра. – alainlompo
Хорошо, спасибо, я понимаю. К сожалению, я новичок в C# и не знаю, как правильно создавать потоки, поэтому, если есть какое-то другое решение, было бы здорово. – Kacper
Тогда это отличная возможность узнать больше о некоторых практиках. Вот ссылка, которая может быть полезна. http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c – alainlompo