Проблема с первой версией заключается в том, что внутри «некоторой логики» вы, вероятно, обращаетесь к объектам WPF - вы не можете этого сделать, доступ к объектам WPF возможен только из того же потока, который их создал.
Проблема со второй версией заключается в том, что вы запускаете фоновый поток, который просит основной поток выполнить всю работу, а затем завершает работу, поэтому вы выполняете всю работу в основном потоке (который также выполняет всю работу пользовательского интерфейса). ) и пользовательский интерфейс зависает, по сути это эквивалентно тому, что BackgroundWorker вообще не используется.
Третья версия, как сказал Джон Скит, - это просто некорректное использование, и она не должна работать так, как вы думаете.
Итак, что вам нужно сделать?
Вам нужно собрать всю информацию из пользовательского интерфейса в основном потоке перед запуском фонового работника, вы можете использовать только простые типы (string, int, double и т. Д.) И поточно-безопасные классы / структуры, вы не можете используйте любые классы WPF в коде, выполняемом BackgroundWorker.
После того, как вы завершили сбор всех данных, которые вы можете вызвать RunWorkerAsync, в вашем обработчике DoWork вы не можете читать данные из пользовательского интерфейса - вы можете получить доступ только к тем данным, которые вы подготовили ранее, также вы не можете записать в пользовательский интерфейс - вам необходимо сохраните его где-нибудь еще (например, член класса) и скопируйте его в пользовательский интерфейс после того, как BackgroundWorker будет завершен.
Единственное исключение из правила "нельзя получить доступ к WPF из другого потока" - это Freezable (и все классы, наследуемые от freezable) после вызова метода Freeze, что делает объект доступным только для чтения и безопасным для потоков.