Добрый день, не могу разобраться с асинхронными методами. Как можно реализовать в приложение такую ситуацию. При запуске создаются два потока один - главный в нем выполняются все пользовательские взаимодействия, во втором потоке как я предполагается должен быть реализован какой то сервис, который бы работал до закрытия приложения. В этом потоке должен быть метод или свойство которое реализует получение переменной (объект класса) и добавляет эту переменную в GUI. Так же в некоторый момент этот сервис должен сам отправить данные и отобразить в GUI что данные отправлены в виде аналогичного полученного класса.
К примеру наверное сервис должен выглядеть так:
public class static Service
{
// метод по получению объекта данных
public static async Task<Model> InPutAsync(Model model)
{
}
// модель по отправке объекта дынных
public static async Task<bool> OutPutAsync(Model model)
{
}
}
Модель:
public class Model
{
public double Sum;
public string Transfer;
}
Для примера такого сервиса возьмемся запускать FileSystemWatcher, который будет отслеживать изменения в нужной папке у нужных типов файлов.
Создадим такой класс
public class FolderWatcher
{
private readonly string _pathFolder;
private readonly IProgress<string> _progress;
private readonly CancellationToken _cancellationToken;
//ctor
public FolderWatcher(string pathFolder, IProgress<string> progress, CancellationToken cancellationToken)
{
if (String.IsNullOrEmpty(pathFolder)) throw new ArgumentNullException(nameof(pathFolder));
if (progress == null) throw new ArgumentNullException(nameof(progress));
_pathFolder = pathFolder;
_progress = progress;
_cancellationToken = cancellationToken;
}
public void Watch(string filter)
{
if (String.IsNullOrEmpty(filter)) throw new ArgumentNullException(nameof(filter));
using (var watcher = new FileSystemWatcher(_pathFolder, filter))
{
watcher.Created += FileCreatedChangedDeleted;
watcher.Changed += FileCreatedChangedDeleted;
watcher.Deleted += FileCreatedChangedDeleted;
watcher.Renamed += FileRenamed;
watcher.IncludeSubdirectories = false;
watcher.EnableRaisingEvents = true;
_progress.Report($"Начинаю следить за {_pathFolder}");
while (true)
{
if (_cancellationToken.IsCancellationRequested) break;
}
_progress.Report("Закончил следить.");
}
}
private void FileRenamed(object sender, RenamedEventArgs e)
{
_progress.Report($"Переименован файл: {e.OldName} в {e.Name}");
}
private void FileCreatedChangedDeleted(object sender, FileSystemEventArgs e)
{
_progress.Report($"Файл {e.FullPath} был {e.ChangeType}");
}
}
Вьюмодель будет такой
public class MainViewModel : INotifyPropertyChanged
{
private CancellationTokenSource _tokenSource;
private bool _isWatching;
public event PropertyChangedEventHandler PropertyChanged;
//ctor
public MainViewModel()
{
FillFileTypes();
}
//Properties
/// <summary>
/// Путь к выбранной папке
/// </summary>
private string _SelectedFolder;
public string SelectedFolder
{
get { return _SelectedFolder; }
set
{
_SelectedFolder = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedFolder)));
StartWatchCommand.RaiseCanExecuteChanged();
}
}
/// <summary>
/// Сообщеня для листбокс
/// </summary>
private ObservableCollection<string> _Messages;
public ObservableCollection<string> Messages
{
get { return _Messages; }
set
{
_Messages = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Messages)));
}
}
/// <summary>
/// Список для комбобокса
/// </summary>
private List<string> _FileTypes;
public List<string> FileTypes
{
get { return _FileTypes; }
set
{
_FileTypes = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FileTypes)));
}
}
/// <summary>
/// Выбранный в комбобксе тип файлов
/// </summary>
private string _SelectedFileType;
public string SelectedFileType
{
get { return _SelectedFileType; }
set
{
_SelectedFileType = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedFileType)));
}
}
//Commands
/// <summary>
/// Команда запуска слежения за папкой
/// </summary>
private RelayCommand _StartWatch;
public RelayCommand StartWatchCommand
{
get => _StartWatch = _StartWatch ?? new RelayCommand(OnStartWatch, CanStartWatch);
}
private bool CanStartWatch()
{
if (String.IsNullOrEmpty(SelectedFolder) || _isWatching)
{
return false;
}
return true;
}
private async void OnStartWatch()
{
//кнопки
_isWatching = true;
StartWatchCommand.RaiseCanExecuteChanged();
StopWatchCommand.RaiseCanExecuteChanged();
//новые сообщения
Messages = new ObservableCollection<string>();
//готовим к запуску сервиса
IProgress<string> progress = new Progress<string>(s => Messages.Add(s));
_tokenSource = new CancellationTokenSource();
CancellationToken cancellationToken = _tokenSource.Token;
try
{
//запуск сервиса
await Task.Run(() =>
{
FolderWatcher folderWatcher = new FolderWatcher(SelectedFolder, progress, cancellationToken);
folderWatcher.Watch(SelectedFileType);
});
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
/// <summary>
/// Команда останова слежения за папкой
/// </summary>
private RelayCommand _StopWatch;
public RelayCommand StopWatchCommand
{
get => _StopWatch = _StopWatch ?? new RelayCommand(OnStopWatch, CanStopWatch);
}
private bool CanStopWatch()
{
if (!_isWatching)
{
return false;
}
return true;
}
private void OnStopWatch()
{
_isWatching = false;
StartWatchCommand.RaiseCanExecuteChanged();
StopWatchCommand.RaiseCanExecuteChanged();
_tokenSource.Cancel();
}
//Methods
private void FillFileTypes()
{
FileTypes = new List<string>
{
"*.*",
"*.txt",
"*.jpg"
};
SelectedFileType = FileTypes.First();
}
/// <summary>
/// Новое значение для выбранной папки
/// </summary>
/// <param name="selectedPath">путь к папке</param>
public void SetFolder(string selectedPath)
{
SelectedFolder = selectedPath;
}
}
Простейший XAML такой
<Canvas>
<Button x:Name="_buttonSelectFolder"
Content="Папка"
Canvas.Left="386"
Canvas.Top="23"
Width="75"
Click="_buttonSelectFolder_Click" />
<TextBox Height="23"
Canvas.Left="53"
Text="{Binding SelectedFolder}"
Canvas.Top="20"
Width="319" />
<Button Content="Запустить"
Canvas.Left="80"
Canvas.Top="90"
Width="75"
Command="{Binding StartWatchCommand, Mode=OneTime}" />
<Button Content="Остановить"
Canvas.Left="195"
Canvas.Top="90"
Width="75"
Command="{Binding StopWatchCommand, Mode=OneTime}" />
<ListBox Height="170"
Canvas.Left="53"
Canvas.Top="124"
Width="408"
ItemsSource="{Binding Messages}" />
<ComboBox Canvas.Left="386"
Canvas.Top="56"
Width="75"
ItemsSource="{Binding FileTypes}"
SelectedItem="{Binding SelectedFileType}" />
<TextBlock Canvas.Left="302"
Text="Тип файлов: "
Canvas.Top="62" />
</Canvas>
Кодбихайнд такой
public partial class MainWindow : Window
{
private readonly MainViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
_viewModel = new MainViewModel();
this.DataContext = _viewModel;
}
private void _buttonSelectFolder_Click(object sender, RoutedEventArgs e)
{
var folderDialog = new System.Windows.Forms.FolderBrowserDialog();
folderDialog.ShowNewFolderButton = false;
folderDialog.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
_viewModel.SetFolder(folderDialog.SelectedPath);
}
}
}
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости