Добавление индикатора выполнения WPF в консольное приложение C#

Короче говоря, из-за изменяющихся бизнес-требований мне нужно иметь возможность показать конечному пользователю ход процесса архивирования файлов, управляемого консольным приложением C#. Консольное приложение по существу получает список локальных файлов из базы данных, а затем копирует их в папку архива. Первоначально предполагалось, что это фоновый процесс, запускаемый запланированной задачей. Однако теперь пользователи могут запускать его вручную с различными аргументами из командной строки, поэтому недавно передо мной стояла задача сообщить пользователю о состоянии процесса архивирования.

Я думал, что просто использую для этого элемент управления WPF ProgressBar, но теперь я хожу по кругу, пытаясь найти лучший способ сделать это. Я работал с ответом @JamesWilkins здесь: окно WPF из консольного проекта?

Я добавил окно ProgressBar в консольное приложение и добавил следующее в метод Main в консоли (упрощено для ясности):

[STAThread]
static void Main(string[] args)
{

    // EXISTING CONSOLE LOGIC
    ParseCommandLineArgs();
    Configure();

    // ADDED
    InitializeWindows(); // opens the WPF window and waits here

    // EXISTING CONSOLE LOGIC 
    BeginArchival();        
}

static void InitializeWindows()
{
    WinApp = new Application();
    WinApp.Run(ProgressBar = new ProgressBar()); // blocking call
}

Затем в коде ProgressBar.xaml:

public partial class ProgressBar : Window
{
    public ProgressBar()
    {
        InitializeComponent();
    }

    private void ProgressBar_OnContentRendered(object sender, EventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.WorkerReportsProgress = true;
        worker.DoWork += worker_DoWork;
        worker.ProgressChanged += worker_ProgressChanged;

        worker.RunWorkerAsync();
    }

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        // foreach file that is archived, report progress to the 
        // ProgressBar.
        for (int i = 0; i < 100; i++)
        {
            (sender as BackgroundWorker).ReportProgress(i);
        }
    }

    private void worker_ProgressChanged(object sender, 
        ProgressChangedEventArgs e)
    {
        PbArchiveStatus.Value = e.ProgressPercentage;
    }
}

Процесс ожидает в методе InitializeWindows() до тех пор, пока индикатор выполнения не закроется, поэтому он не затрагивает какую-либо логику архивирования, для которой мне нужен индикатор выполнения для отображения прогресса. Кажется, мне по существу нужно поместить всю существующую консольную логику в метод ProgressBar.worker_DoWork(), но в этот момент мой мозг начинает болеть, поэтому я подумал, что протяну руку.

Я на правильном пути, или есть лучший способ добавить индикатор выполнения на основе графического интерфейса в консольную утилиту? Дайте мне знать, если я могу что-то прояснить.


person riffmcgriff    schedule 20.09.2017    source источник
comment
Что обычно отображается в окне консоли? Это просто внутреннее приложение, в котором вы можете создать собственный тип индикатора выполнения в консоли, например [||||||||||| ]   -  person Sam Marion    schedule 20.09.2017
comment
Нельзя ли просто писать прогресс в консоль? Таким образом, вы не превратите консольное приложение (которое явно работает без графического интерфейса, например, через удаленный сеанс) в ущербное приложение для Windows. Если индикатор выполнения WPF уже определен, не можете ли вы просто превратить свое приложение в полноценное приложение для Windows, вместо того, чтобы работать наполовину в консоли, наполовину в окне?   -  person poke    schedule 20.09.2017
comment
Единственная причина, по которой я изначально сделал это консольным приложением, заключается в том, что они хотели, чтобы оно запускалось как запланированное задание. В итоге они удалили это требование и сказали, что хотят иметь возможность запускать его вручную. У меня действительно был текстовый индикатор выполнения в консоли. Проблема заключалась в том, что если пользователь щелкнул окно консоли в любой момент, это, по сути, сломало индикатор выполнения. Я просто решил, что индикатор выполнения на основе графического интерфейса выглядит лучше и является более чистым и надежным решением, но он оказался немного более сложным, чем я думал изначально.   -  person riffmcgriff    schedule 21.09.2017
comment
Чтобы было ясно, я понимаю, что это не идеально, но мне нужно иметь возможность сохранить все то же самое, что касается конечного пользователя (запуск исполняемого файла с аргументами командной строки).   -  person riffmcgriff    schedule 21.09.2017
comment
Я могу изменить тип вывода проекта на Приложение Windows, как вы сказали @poke, но это все еще заставляет меня задуматься, как лучше всего интегрировать индикатор выполнения.   -  person riffmcgriff    schedule 21.09.2017
comment
Я больше думал о том, чтобы начать правильный (новый) проект приложения Windows, создать там правильный (простой) пользовательский интерфейс и затем перенести в него логику приложения.   -  person poke    schedule 21.09.2017
comment
Кажется, мне нужно поместить всю существующую консольную логику в метод ProgressBar.worker_DoWork() -- ну, вам нужно поместить ее где-нибудь. Не совсем понятно, какой ответ вам нужен. Дело в том, что вы должны решить, пишете ли вы консольную программу или программу WPF, а не смешивать их. Вы можете отображать прогресс в консольной программе, но не с функциями WPF. Если вы хотите использовать функции WPF, вам действительно нужно просто создать обычную программу с графическим интерфейсом, которая использует WPF. Пока вы придерживаетесь одного или другого, уже есть достаточно информации об индикаторе прогресса.   -  person Peter Duniho    schedule 21.09.2017
comment
И чтобы было ясно: да, вы можете показать графический интерфейс из консольной программы, но в конце концов это никогда не работает правильно. Лучше избегать такого подхода Франкенштейна.   -  person Peter Duniho    schedule 21.09.2017