Подтвердить что ты не робот

Как создать и показать окна WPF для отдельных потоков?

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

В WinForms это достигается посредством:

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

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

4b9b3361

Ответ 1

Как 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 вне потока (делегата), а затем вызовите его, например:

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()

Ответ 2

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

"Для нашего упрощенного решения есть один улов. Закрытие отдельного окна делает НЕ завершение этого диспетчера потоков Windows, поэтому поток продолжает работать, и после закрытия всех окон процесс не будет завершен и станет" призрачным "процессом. [The] Простое (и не правильное) решение состоит в том, чтобы пометить наши потоки как фон (используя 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

Я думаю, что нашел ответ. Посмотрите на Jon Skeet ответ в этом question.

В основном вы делаете это в своем методе запуска потока:

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

Ответ 4

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

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

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(){};
}

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