Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多线程调度程序_C#_Wpf_Multithreading_Progress Bar_Dispatcher - Fatal编程技术网

C# 多线程调度程序

C# 多线程调度程序,c#,wpf,multithreading,progress-bar,dispatcher,C#,Wpf,Multithreading,Progress Bar,Dispatcher,我有一个带有后台工作程序的多线程应用程序,我用它来显示一个启动屏幕,以处理主窗口的创建 我想在程序中更新线程“u”中的进度条,因此每次我想从线程“u”更新进度条时,都必须调用进度条控件。 所以这意味着我不必特别使用backgroundWorker\u DoWork 我遇到的问题是,调用backgroundWorker_RunWorkerCompleted事件时,无法显示主窗口form2 我想问题出在调度员身上 public partial class App : Application {

我有一个带有后台工作程序的多线程应用程序,我用它来显示一个启动屏幕,以处理主窗口的创建

我想在程序中更新线程“u”中的进度条,因此每次我想从线程“u”更新进度条时,都必须调用进度条控件。 所以这意味着我不必特别使用backgroundWorker\u DoWork

我遇到的问题是,调用backgroundWorker_RunWorkerCompleted事件时,无法显示主窗口form2

我想问题出在调度员身上

public partial class App : Application
{
    public BackgroundWorker backgroundWorker;
    private SplashScreenWindow splashScreen;

    public static EventWaitHandle initWaitHandle = new AutoResetEvent(false);
    public MainWindow Form2 { get; set; } 
    [DllImport("kernel32.dll")]
    private static extern bool AllocConsole();

    protected override void OnStartup(StartupEventArgs e)
    {
        backgroundWorker = new BackgroundWorker();
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
        backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
        backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);

        splashScreen = new SplashScreenWindow();
        splashScreen.ShowInTaskbar = false;
        splashScreen.ResizeMode = ResizeMode.NoResize;
        splashScreen.WindowStyle = WindowStyle.None;
        splashScreen.Topmost = true;
        splashScreen.Width =  (SystemParameters.PrimaryScreenWidth) / 2.5;
        splashScreen.Height = (SystemParameters.PrimaryScreenHeight) / 2.5;
        splashScreen.Show();
        base.OnStartup(e);

        backgroundWorker.RunWorkerAsync();

        Thread u = new Thread(new ThreadStart(interface_process));
        u.SetApartmentState(ApartmentState.STA);
        u.Start();
    }

    public void interface_process()
    {
        MainWindow form2 = new MainWindow();
        this.Form2 = form2;
        System.Windows.Threading.Dispatcher.Run();
    }

    void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        splashScreen.Close();
        this.Form2.Invoke((Action)delegate()
        {
            this.Form2.Show(); // does not work
            System.Windows.Threading.Dispatcher.Run();
        });

    }

    void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        splashScreen.ValueProgressBar = e.ProgressPercentage;
    }

    void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i <= 100; i += 10)
        {
            backgroundWorker.ReportProgress(i, "Chargement en cours : " + i);
            Thread.Sleep(500);
        }
    }
}

我不清楚您发布的代码将如何编译,因为WPF窗口类上没有Invoke方法。这将在此处的代码中导致编译时错误:

void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    splashScreen.Close();
    this.Form2.Invoke((Action)delegate()
    {
        this.Form2.Show(); // does not work
        System.Windows.Threading.Dispatcher.Run();
    });
}
如果更改了上述代码,使方法中的第二条语句读取this.Form2.Dispatcher.InvokeActiondelegate(即,使用拥有Form2对象的Dispatcher对象),那么不仅代码应该编译,调用this.Form2.Show也应该工作。请注意,不需要第二次调用Dispatcher.Run,实际上应该避免

因此,该方法的正确实现如下所示:

void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    splashScreen.Close();
    this.Form2.Dispatcher.Invoke((Action)delegate()
    {
        this.Form2.Show(); // works fine
    });
}
现在,也就是说……在我看来,整个方法是有缺陷的。你真的应该在你的程序中有一个UI线程。如果希望在显示初始屏幕时首先发生某些事情,则将初始屏幕窗口设置为显示的第一个窗口,运行后台任务,然后在完成后在同一线程中显示主窗口

下面是一个您似乎正在尝试做的事情的示例,但编写时只使用主UI线程和正常的WPF启动机制

假设我们从VisualStudio中的一个普通WPF项目开始。这其中已经有一个应用程序类和一个主窗口类。我们只需要编辑它就可以了

首先,我们需要一个闪屏窗口。大部分配置可以在XAML中完成;因为您希望根据屏幕大小计算宽度和高度,所以我最容易将其放入构造函数中。结果是这样的:

void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    splashScreen.Close();
    this.Form2.Dispatcher.Invoke((Action)delegate()
    {
        this.Form2.Show(); // works fine
    });
}
SplashScreenWindow.xaml:

现在,上面的类是我们希望首先显示的类。因此,我们通过更改StartupUri属性来编辑应用程序类的XAML:

<Application x:Class="TestSingleThreadSplashScreen.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="SplashScreenWindow.xaml">
    <Application.Resources>

    </Application.Resources>
</Application>
这里唯一棘手的事情是,在显示主窗口后,必须关闭启动屏幕窗口。否则,WPF会认为您已经关闭了最后一个窗口,从技术上讲,您会关闭该程序。通过在关闭闪屏窗口之前显示主窗口,程序将继续运行


在我看来,这是一种更好的方法,因为它与正常的WPF机制一起工作,而不是试图颠覆和/或绕过它们。它利用了程序启动时自动创建的调度程序,不需要额外的UI线程等。哦,而且……它可以工作。就是这样

我不能说这不是一个很好的错误描述。你试了什么?发生了什么事?很抱歉没有指定,当我试图显示Form2时,接口_进程中没有发生任何事情。主窗口未显示,但应用程序正在运行。错误太多。。。首先,后台工作线程将在主线程中完成,所以您不需要调用。System.Windows.Threading.Dispatcher.Run;-这是什么意思?这行可以删除,它不做任何事情。你不需要u线程来更新进度条。进度条必须从主威胁更新!我认为您还应该在runworkerCompleted上创建主窗口mw=新的主窗口;mw.show;谢谢你的建议,我必须保留“u”线程,因为任务必须由我的程序完成。我解决这个问题的方法是先显示我的主窗口,然后再关闭启动屏幕,看看你是如何说的,它是如何工作的。
<Application x:Class="TestSingleThreadSplashScreen.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="SplashScreenWindow.xaml">
    <Application.Resources>

    </Application.Resources>
</Application>
public partial class App : Application
{
    private SplashScreenWindow SplashScreen { get { return (SplashScreenWindow)this.MainWindow; } }

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        BackgroundWorker backgroundWorker = new BackgroundWorker();

        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.DoWork += backgroundWorker_DoWork;
        backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
        backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
        backgroundWorker.RunWorkerAsync();
    }

    void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        new MainWindow().Show();
        SplashScreen.Close();
    }

    void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        SplashScreen.ValueProgressBar = e.ProgressPercentage;
    }

    void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker backgroundWorker = (BackgroundWorker)sender;

        for (int i = 0; i <= 100; i += 10)
        {
            backgroundWorker.ReportProgress(i, "Chargement en cours : " + i);
            Thread.Sleep(500);
        }
    }
}