子窗口阻塞主线程

时间:2017-07-19 10:45:35

标签: c# wpf windows multithreading

我正在使用我在网上找到的用户控件来表达处理。

我要做的是显示一个包含此用户控件的窗口,直到主线程完成处理。

这是用户控制代码:

public partial class CircularProgressBar
{
    #region Data

    private readonly DispatcherTimer animationTimer;

    #endregion

    #region Constructor

    public CircularProgressBar()
    {
        InitializeComponent();

        animationTimer = new DispatcherTimer( DispatcherPriority.ContextIdle, Dispatcher);
        animationTimer.Interval = new TimeSpan(0, 0, 0, 0, 75);
    }

    #endregion

    #region Private Methods

    private void Start()
    {
        Mouse.OverrideCursor = Cursors.Wait;
        animationTimer.Tick += HandleAnimationTick;
        animationTimer.Start();
    }

    private void Stop()
    {
        animationTimer.Stop();
        Mouse.OverrideCursor = Cursors.Arrow;
        animationTimer.Tick -= HandleAnimationTick;
    }

    private void HandleAnimationTick(object sender, EventArgs e)
    {
        SpinnerRotate.Angle = (SpinnerRotate.Angle + 36) % 360;
    }

    private void HandleLoaded(object sender, RoutedEventArgs e)
    {
        const double offset = Math.PI;
        const double step = Math.PI * 2 / 10.0;

        SetPosition(C0, offset, 0.0, step);
        SetPosition(C1, offset, 1.0, step);
        SetPosition(C2, offset, 2.0, step);
        SetPosition(C3, offset, 3.0, step);
        SetPosition(C4, offset, 4.0, step);
        SetPosition(C5, offset, 5.0, step);
        SetPosition(C6, offset, 6.0, step);
        SetPosition(C7, offset, 7.0, step);
        SetPosition(C8, offset, 8.0, step);
    }

    private void SetPosition(Ellipse ellipse, double offset, double posOffSet, double step)
    {
        ellipse.SetValue(Canvas.LeftProperty, 50.0 + Math.Sin(offset + posOffSet * step) * 50.0);
        ellipse.SetValue(Canvas.TopProperty, 50 + Math.Cos(offset + posOffSet * step) * 50.0);
    }

    private void HandleUnloaded(object sender, RoutedEventArgs e)
    {
        Stop();
    }

    private void HandleVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        bool isVisible = (bool)e.NewValue;

        if (isVisible)
            Start();
        else
            Stop();
    }

    #endregion
}

XAML:

<UserControl Height="Auto" Width="Auto" Background="Transparent" IsVisibleChanged="HandleVisibleChanged">
    <Grid x:Name="LayoutRoot" Background="Transparent" ToolTip="Searching...."  HorizontalAlignment="Center" VerticalAlignment="Center">
        <Canvas RenderTransformOrigin="0.5,0.5"
                HorizontalAlignment="Center"
             VerticalAlignment="Center" Width="120"
             Height="120" Loaded="HandleLoaded"
                Unloaded="HandleUnloaded"  >
            <Ellipse x:Name="C0" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="Black" Opacity="1.0"/>
            <Ellipse x:Name="C1" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.9"/>
            <Ellipse x:Name="C2" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.8"/>
            <Ellipse x:Name="C3" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.7"/>
            <Ellipse x:Name="C4" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.6"/>
            <Ellipse x:Name="C5" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.5"/>
            <Ellipse x:Name="C6" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.4"/>
            <Ellipse x:Name="C7" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.3"/>
            <Ellipse x:Name="C8" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.2"/>
            <Canvas.RenderTransform>
                <RotateTransform x:Name="SpinnerRotate"
                     Angle="0" />
            </Canvas.RenderTransform>
        </Canvas>
    </Grid>
</UserControl>

我在窗口中使用此用户控件并在使用以下方式开始处理时调用此窗口:

private void ThreadStartingPoint()
{
    Window.Show();
    Window.Focus();
    System.Windows.Threading.Dispatcher.Run();
}

这阻止了主线程的执行,我不知道我做了什么错误,因为我是新手。

1 个答案:

答案 0 :(得分:1)

Dispatcher.Run肯定是封锁的。你不能在没有阻塞的情况下在主线程上调用这个方法。

如果你想出于某种原因在专用线程上创建一个新窗口,你可以参考@Reed Copsey的博客文章:

在单独的主题中启动WPF窗口,第1部分: http://reedcopsey.com/2011/11/28/launching-a-wpf-window-in-a-separate-thread-part-1/

它解释了如何正确地做到这一点:

// Create a thread
Thread newWindowThread = new Thread(new ThreadStart(() =>
{
    // Create our context, and install it:
    SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));

    Window1 tempWindow = new Window1();
    tempWindow.Content = new CircularProgressBar();
    // When the window closes, shut down the dispatcher
    tempWindow.Closed += (s, e) =>
    Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);

    tempWindow.Show();
    // Start the Dispatcher Processing
    System.Windows.Threading.Dispatcher.Run();
}));
// Set the apartment state
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();