Я недавно сделал нечто подобное для проверки службы Windows.Это оказалось очень простым в реализации.
В вашем случае я вижу необходимость в следующем.
Файл - его единственная цель - загрузить файл и уведомить об изменениях.
FileManager - ведет список файлов и добавляет новые, удаляя ect.
public class File : INotifyPropertyChanged
{
private readonly string _fileName;
private Thread _thread;
private Task _task;
private bool _cancelled;
private TaskStatus _taskStatus;
private int _taskProgress;
private int _taskTotal;
public event PropertyChangedEventHandler PropertyChanged;
public File(string fileName)
{
_fileName = fileName;
TaskStatus = TaskStatus.NotStarted;
}
public TaskStatus TaskStatus
{
get { return _taskStatus; }
private set
{
_taskStatus = value;
PropertyChanged.Raise(this, x => x.TaskStatus);
}
}
public int TaskProgress
{
get { return _taskProgress; }
private set
{
_taskProgress = value;
PropertyChanged.Raise(this, x => x.TaskProgress);
}
}
public int TaskTotal
{
get { return _taskTotal; }
private set
{
_taskTotal = value;
PropertyChanged.Raise(this, x => x.TaskTotal);
}
}
public void StartTask()
{
_cancelled = false;
//.Net 4 - task parallel library - nice
_task = new Task(DownloadFile, TaskCreationOptions.LongRunning);
_task.Start();
//.Net Other
_thread = new Thread(DownloadFile);
_thread.Start();
}
public void CancelTask()
{
_cancelled = true;
}
private void DownloadFile()
{
try
{
TaskStatus = TaskStatus.Running;
var fileLength = _fileName.Length;
TaskTotal = fileLength;
for (var i = 0; i < fileLength; i++)
{
if (_cancelled)
{
TaskStatus = TaskStatus.Cancelled;
return;
}
//Some work to download the file
Thread.Sleep(1000); //sleep for the example instead
TaskProgress = i;
}
TaskStatus = TaskStatus.Completed;
}
catch (Exception ex)
{
TaskStatus = TaskStatus.Error;
}
}
}
public enum TaskStatus
{
NotStarted,
Running,
Completed,
Cancelled,
Error
}
public static class NotifyPropertyChangedExtention
{
public static void Raise<T, TP>(this PropertyChangedEventHandler pc, T source, Expression<Func<T, TP>> pe)
{
if (pc != null)
{
pc.Invoke(source, new PropertyChangedEventArgs(((MemberExpression)pe.Body).Member.Name));
}
}
}
Прелесть этого в том, что вам никогда не нужно обновлять пользовательский интерфейс из фонового потока.То, что вы обновляете, это свойства только для чтения, которые будет записывать только фоновый класс.Все, что находится вне этого класса, может только читать, так что вам не нужно беспокоиться о блокировке.Система привязки пользовательского интерфейса получит уведомление об изменении свойства при поднятии PropertyChanged, а затем прочитает значение.
Теперь для менеджера
public class FileManager
{
public ObservableCollection<File> ListOfFiles { get; set; }
public void AddFile(string fileName)
{
var file = new File(fileName);
file.PropertyChanged += FilePropertyChanged;
file.StartTask();
ListOfFiles.Add(file);
}
void FilePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "TaskStatus")
{
var file = (File) sender;
if (file.TaskStatus==TaskStatus.Completed)
{
RemoveFile(file);// ??? automatically remove file from list on completion??
}
}
}
public void RemoveFile(File file)
{
if (file.TaskStatus == TaskStatus.Running)
{
file.CancelTask();
}
//unbind event
file.PropertyChanged -= FilePropertyChanged;
ListOfFiles.Remove(file);
}
}
Теперь все, что вам нужно сделать в вашей модели представления, это открыть ListOfFiles из FileManager, который является наблюдаемой коллекцией.Уведомления от него сообщат системе привязки, когда пользовательский интерфейс должен обновить.
Просто свяжите ListOfFiles с ListView или аналогичным, добавьте таблицу данных для класса File, которая позволит представлению списка знать, как отображать каждый из них.file.
Ваш сервер WCF и модель представления должны иметь ссылку на тот же File Manager, WCF добавляет и удаляет файлы, viewmodel делает ListOfFiles доступными для пользовательского интерфейса.
Это просто грубый взлом, чтобы донести концепцию.Вам нужно будет добавлять свои материалы по своему усмотрению.
Дайте мне знать, если это помогло.