Как создать и показать окна WPF в отдельных потоках? - PullRequest
31 голосов
/ 10 июля 2009

Мне нужно создать два (или более) окна WPF из одного процесса. Но окна должны обрабатываться отдельными потоками, потому что они не должны блокировать друг друга. Как мне это сделать?

В WinForms это достигается с помощью:

  • Создать новую тему
  • Создать форму из новой темы
  • Вызовите Application.Run с формой в качестве параметра

Но как мне сделать то же самое в WPF?

Ответы [ 4 ]

45 голосов
/ 10 июля 2009

As msdn состояния:

private void NewWindowHandler(object sender, RoutedEventArgs e)
{       
    Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
    newWindowThread.SetApartmentState(ApartmentState.STA);
    newWindowThread.IsBackground = true;
    newWindowThread.Start();
}

private void ThreadStartingPoint()
{
    Window1 tempWindow = new Window1();
    tempWindow.Show();       
    System.Windows.Threading.Dispatcher.Run();
}

EDIT: Это старый ответ, но так как его часто посещают, я мог бы подумать о следующих модификациях / улучшениях (не тестировалось).

Если вы хотите закрыть такое окно, просто сохраните ссылку на объект Window снаружи потока (делегата), а затем вызовите close для него, что-то вроде этого:

void CloseWindowSafe(Window w)
{
    if (w.Dispatcher.CheckAccess())
        w.Close();
    else
        w.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(w.Close));
}

// ...
CloseWindowSafe(tempWindow);

Если новый поток может быть прерван (принудительно прерван), в соответствии с вопросом в комментариях:

private void ThreadStartingPoint()
{
    try{
        Window1 tempWindow = new Window1();
        tempWindow.Show();       
        System.Windows.Threading.Dispatcher.Run();
    }
    catch(ThreadAbortException)
    {
        tempWindow.Close();
        System.Windows.Threading.Dispatcher.InvokeShutdown();
    }
    //the CLR will "rethrow" thread abort exception automatically
}

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: не делайте этого дома, прерывание потоков (почти всегда) противоречит лучшим практикам. Потоки должны корректно обрабатываться с помощью любого из различных методов синхронизации, или в этом случае, просто с помощью вызванного window.Close()

15 голосов
/ 05 февраля 2014

Во что бы то ни стало, так как этот ответ является первым результатом, предоставленным Google. Я также хотел бы добавить следующее взятое из Elogene Prystupa's Weblog :

"В нашем упрощенном решении есть одна загвоздка. При закрытии определенного окна НЕ завершает работу диспетчера потоков этого окна, поэтому поток продолжает работать и, после закрытия всех окон, процесс не завершится и будет стать призрачным процессом. [Простое (и не правильное) решение этой проблемы - пометить наши потоки как фоновые (используя thread.IsBackground = true;). Это заставит их завершиться, когда завершится основной поток пользовательского интерфейса.

Правильная реализация изящно отключит диспетчер, когда он больше не нужен. Приведенный ниже код является примером стратегии завершения работы диспетчера при закрытии окна : "

private void OnCreateNewWindow(object sender, RoutedEventArgs e)
{
    Thread thread = new Thread(() =>
    {
        Window1 w = new Window1();
        w.Show();

        w.Closed += (sender2, e2) =>
            w.Dispatcher.InvokeShutdown();

        System.Windows.Threading.Dispatcher.Run();
    });

    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
}
3 голосов
/ 10 июля 2009

Я думаю, что нашел ответ. Посмотрите на ответ Джона Скита в этом вопросе .

По сути, вы делаете это в методе запуска потока:

private void ThreadStartingPoint()
{
    Window1 tempWindow = new Window1();
    tempWindow.Show();       
    System.Windows.Threading.Dispatcher.Run();
}
2 голосов
/ 18 февраля 2012

Именно то, что я искал.

Я делаю это так:

App.xaml.cs

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
            newWindowThread.SetApartmentState(ApartmentState.STA);
            newWindowThread.IsBackground = true;
            newWindowThread.Start();

            var window = new MainWindow(newWindowThread);
            window.DataContext = new MainWindowViewModel(window);
            window.Show();
        }

        private void ThreadStartingPoint()
        {
            SplashWindow tempWindow = new SplashWindow();
            tempWindow.Show();
            System.Windows.Threading.Dispatcher.Run();
        }
    }

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow(Thread splashWindowThread)
    {
        InitializeComponent();

        MyInializaComponent();

        splashWindowThread.Abort();
    }

//void DoStuff(){};
}

Мне нужно, чтобы заставка исчезла после того, как программа выполнила всю загрузку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...