Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.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_Dispatcher - Fatal编程技术网

C# 鼠标悬停在加载屏幕上

C# 鼠标悬停在加载屏幕上,c#,wpf,multithreading,dispatcher,C#,Wpf,Multithreading,Dispatcher,我有一个加载屏幕,它在一个单独的线程上运行: public partial class LoadingScreen : Window { #region Variables private static Thread _thread; private static LoadingScreen _loading; private static bool _isIndeterminate; #endregion public LoadingScr

我有一个
加载屏幕
,它在一个单独的
线程上运行

public partial class LoadingScreen : Window
{
    #region Variables

    private static Thread _thread;
    private static LoadingScreen _loading;
    private static bool _isIndeterminate;

    #endregion

    public LoadingScreen()
    {
        InitializeComponent();
    }

    #region Methods

    public static void ShowSplash(bool isIndeterminate = false)
    {
        _isIndeterminate = isIndeterminate;

        _thread = new Thread(OpenSplash)
        {
            IsBackground = true,
            Name = "Loading"
        };
        _thread.SetApartmentState(ApartmentState.STA);
        _thread.Start();
    }

    private static void OpenSplash()
    {
        _loading = new LoadingScreen();
        _loading.ProgressBar.IsIndeterminate = _isIndeterminate;
        _loading.ShowDialog();

        _loading.Dispatcher.Invoke(new Action(Dispatcher.Run));
    }

    public static void CloseSplash()
    {
        if (_loading == null || _thread == null)
            return;

        _loading.Dispatcher.Invoke(new Action(() => { _loading.Close(); }));
        _loading.Dispatcher.InvokeShutdown();
        _loading = null;
    }

    public static void Update(int value, string description)
    {
        Update((double)value, description);
    }

    public static void Update(double value, string description)
    {
        if (_loading == null)
            return;

        _loading.Dispatcher.Invoke((Action)delegate
        {
            var da = new DoubleAnimation(value, new Duration(TimeSpan.FromMilliseconds(Math.Abs(_loading.ProgressBar.Value - value) * 12)))
            {
                EasingFunction = new PowerEase { Power = 3 }
            };

            _loading.ProgressBar.BeginAnimation(RangeBase.ValueProperty, da);
            _loading.TextBlock.Text = description;
        });
    }

    public static void Status(bool isIndeterminate)
    {
        if (_loading == null)
            return;

        _loading.Dispatcher.Invoke((Action)delegate
       {
           _loading.ProgressBar.IsIndeterminate = isIndeterminate;
       });
    }

    #endregion

    private void SplashScreen_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DragMove();
    }

    private void RestoreButton_OnClick(object sender, RoutedEventArgs e)
    {
        _loading.Dispatcher.Invoke((Action)delegate
        {
            if (_loading.MiddleRowDefinition.Height == new GridLength(1, GridUnitType.Star))
            {
                _loading.MiddleRowDefinition.Height = new GridLength(0);
                _loading.RestoreButton.Content = "R";
                _loading.Height = 69;
            }
            else
            {
                _loading.MiddleRowDefinition.Height = new GridLength(1, GridUnitType.Star);
                _loading.RestoreButton.Content = "A"; //I removed my vector to test.
                _loading.Height = 200;
            }
        });
    }

    private void MinimizeButton_OnClick(object sender, RoutedEventArgs e)
    {
        _loading.Dispatcher.Invoke((Action)delegate
        {
            _loading.WindowState = WindowState.Minimized;
        });
    }
}
Xaml:


当我悬停此
加载屏幕
包含的两个按钮中的一个时,问题就会发生,我甚至没有单击,只是悬停,不到一秒钟后,
Dispatcher.Run()
向我抛出一个
调用线程无法访问此对象,因为另一个线程拥有它。

我测试了有或没有自定义
样式
和(没有)内容(我删除了向量以简化此问题的代码),没有不同的结果

我可以轻松地拖动以移动
窗口
,但不能悬停
按钮
。真奇怪。在使用另一个线程并运行
调度程序时,我是否错过了什么

编辑: 使用
ShowDialog()
而不是
Show()
没有任何作用。
删除
Dispatcher.Run()
会杀死我的应用程序的另一部分(没有其他显示,只有一个白色屏幕)。
删除
STA
会使应用程序崩溃(它需要是STA)

编辑2: 完整的代码是可用的。
该应用程序使用.net 4.0,我忘了这么说。

鼠标悬停发生在GUI线程中,您的按钮逻辑在另一个线程中;解决这个问题,你就会解决问题

DragMove
操作调用回GUI线程。大概是这样的:

public static void SafeOperationToGuiThread(Action operation)
{
   System.Windows.Application.Current?.Dispatcher?.Invoke(operation);
}
称为

 SafeOperationToGuiThread( DragMove );


如果您没有使用C#6(在VS 2015中),则在显示的每个
处进行健全的空检查。

鼠标悬停发生在GUI线程中,您的按钮逻辑在不同的线程中;解决这个问题,你就会解决问题

DragMove
操作调用回GUI线程。大概是这样的:

public static void SafeOperationToGuiThread(Action operation)
{
   System.Windows.Application.Current?.Dispatcher?.Invoke(operation);
}
称为

 SafeOperationToGuiThread( DragMove );


如果您没有使用C#6(在VS 2015中),则在显示的每个
处进行健全的空检查。

,因此这是由于工具提示。这就解释了为什么你必须把鼠标放在上面一小段时间。我会把它加到我的测试中,看看我能想出什么

编辑:我相信这个问题是由于你的方式开始你的线程。您正在从主窗口调用启动屏幕吗?如果是,则需要更改代码的顺序:

  public static void ShowSplash(bool isIndeterminate = false)
    {
        _thread = new Thread(new ThreadStart(OpenSplash))
        {
            IsBackground = true,
            Name = "Loading"
        };

        _thread.SetApartmentState(ApartmentState.STA);
        _thread.Start();
    }

    private static void OpenSplash()
    {
        //Run on another thread.
        _splash = new Splash();
        _isIndeterminate = false;

       _splash.Show();
        System.Windows.Threading.Dispatcher.Run();

        //_splash.Dispatcher.Invoke(new Action(Dispatcher.Run));
        System.Windows.Threading.Dispatcher.Run(); //HERE!
        _splash.Dispatcher.Invoke(() => { _splash.ProgressBar.IsIndeterminate = _isIndeterminate; });

    }
在我最初的帖子中,我是从App.xaml.cs文件创建窗口的,当时没有调度程序在运行,这就是它工作的原因。当从窗口调用它时,它是从主Windows dispatcher线程调用的,按照您设置线程的方式,它总是取消主窗口。当我像这样设置它时,我会得到与您相同的问题。通过更改线程创建,它将按预期工作

有关详细信息,请参阅ShowSplash和OpenSplash方法中的更改

原创帖子:我试图复制你的代码,但我无法让它失败。请看下面我的代码,它在您的系统上工作吗

App.cs

public partial class App : Application
{
    private static Splash _splash;
    private static bool _isIndeterminate = false;
    private static Thread _thread;

    protected override void OnStartup(StartupEventArgs e)
    {
        ShowSplash(true);

        Thread.Sleep(5000);
    }

    public static void ShowSplash(bool isIndeterminate = false)
    {
        _isIndeterminate = isIndeterminate;

        _thread = new Thread(OpenSplash)
        {
            IsBackground = true,
            Name = "Loading"
        };
        _thread.SetApartmentState(ApartmentState.STA);
        _thread.Start();
    }

    private static void OpenSplash()
    {
        //Run on another thread.
        _splash = new Splash();
        _splash.Show();

        _splash.ProgressBar.IsIndeterminate = _isIndeterminate;
        //_splash.Dispatcher.Invoke(new Action(Dispatcher.Run));
        System.Windows.Threading.Dispatcher.Run(); //HERE!
    }

    public static void CloseSplash()
    {
        if (_splash == null || _thread == null)
            return;

        _splash.Dispatcher.Invoke(new Action(() => { _splash.Close(); }));
        _splash.Dispatcher.InvokeShutdown();
        _splash = null;
    }

    public static void Update(int value, string description)
    {
        Update((double)value, description);
    }

    public static void Update(double value, string description)
    {
        if (_splash == null)
            return;

        _splash.Dispatcher.Invoke((Action)delegate
        {
            //It takes 120 ms to progress 10%.
            var da = new DoubleAnimation(value, new Duration(TimeSpan.FromMilliseconds(Math.Abs(_splash.ProgressBar.Value - value) * 12)))
            {
                EasingFunction = new PowerEase { Power = 3 }
            };

            _splash.ProgressBar.BeginAnimation(RangeBase.ValueProperty, da);
            _splash.textBlock.Text = description;
        });
    }


}
Splash.xaml.cs

public partial class Splash : Window
{
    public Splash()
    {
        InitializeComponent();
    }

    private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        this.DragMove();
    }
}
飞溅xaml

<Window x:Class="SplashScreenWPF.Splash"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:SplashScreenWPF"
    mc:Ignorable="d"
    Title="Splash" Height="300" Width="300" MouseLeftButtonDown="Window_MouseLeftButtonDown">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="147*"/>
        <ColumnDefinition Width="145*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="135*"/>
        <RowDefinition Height="134*"/>
    </Grid.RowDefinitions>
    <Button  Margin="30" Grid.Column="0" />
    <Button  Margin="30" Grid.Column="2" />
    <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="30,66,0,0" Grid.Row="1" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
    <ProgressBar x:Name="ProgressBar" Grid.Column="1" HorizontalAlignment="Left" Height="16" Margin="24,66,0,0" Grid.Row="1" VerticalAlignment="Top" Width="100"/>

</Grid>


所以这是由于工具提示。这就解释了为什么你必须把鼠标放在上面一小段时间。我会把它加到我的测试中,看看我能想出什么

编辑:我相信这个问题是由于你的方式开始你的线程。您正在从主窗口调用启动屏幕吗?如果是,则需要更改代码的顺序:

  public static void ShowSplash(bool isIndeterminate = false)
    {
        _thread = new Thread(new ThreadStart(OpenSplash))
        {
            IsBackground = true,
            Name = "Loading"
        };

        _thread.SetApartmentState(ApartmentState.STA);
        _thread.Start();
    }

    private static void OpenSplash()
    {
        //Run on another thread.
        _splash = new Splash();
        _isIndeterminate = false;

       _splash.Show();
        System.Windows.Threading.Dispatcher.Run();

        //_splash.Dispatcher.Invoke(new Action(Dispatcher.Run));
        System.Windows.Threading.Dispatcher.Run(); //HERE!
        _splash.Dispatcher.Invoke(() => { _splash.ProgressBar.IsIndeterminate = _isIndeterminate; });

    }
在我最初的帖子中,我是从App.xaml.cs文件创建窗口的,当时没有调度程序在运行,这就是它工作的原因。当从窗口调用它时,它是从主Windows dispatcher线程调用的,按照您设置线程的方式,它总是取消主窗口。当我像这样设置它时,我会得到与您相同的问题。通过更改线程创建,它将按预期工作

有关详细信息,请参阅ShowSplash和OpenSplash方法中的更改

原创帖子:我试图复制你的代码,但我无法让它失败。请看下面我的代码,它在您的系统上工作吗

App.cs

public partial class App : Application
{
    private static Splash _splash;
    private static bool _isIndeterminate = false;
    private static Thread _thread;

    protected override void OnStartup(StartupEventArgs e)
    {
        ShowSplash(true);

        Thread.Sleep(5000);
    }

    public static void ShowSplash(bool isIndeterminate = false)
    {
        _isIndeterminate = isIndeterminate;

        _thread = new Thread(OpenSplash)
        {
            IsBackground = true,
            Name = "Loading"
        };
        _thread.SetApartmentState(ApartmentState.STA);
        _thread.Start();
    }

    private static void OpenSplash()
    {
        //Run on another thread.
        _splash = new Splash();
        _splash.Show();

        _splash.ProgressBar.IsIndeterminate = _isIndeterminate;
        //_splash.Dispatcher.Invoke(new Action(Dispatcher.Run));
        System.Windows.Threading.Dispatcher.Run(); //HERE!
    }

    public static void CloseSplash()
    {
        if (_splash == null || _thread == null)
            return;

        _splash.Dispatcher.Invoke(new Action(() => { _splash.Close(); }));
        _splash.Dispatcher.InvokeShutdown();
        _splash = null;
    }

    public static void Update(int value, string description)
    {
        Update((double)value, description);
    }

    public static void Update(double value, string description)
    {
        if (_splash == null)
            return;

        _splash.Dispatcher.Invoke((Action)delegate
        {
            //It takes 120 ms to progress 10%.
            var da = new DoubleAnimation(value, new Duration(TimeSpan.FromMilliseconds(Math.Abs(_splash.ProgressBar.Value - value) * 12)))
            {
                EasingFunction = new PowerEase { Power = 3 }
            };

            _splash.ProgressBar.BeginAnimation(RangeBase.ValueProperty, da);
            _splash.textBlock.Text = description;
        });
    }


}
Splash.xaml.cs

public partial class Splash : Window
{
    public Splash()
    {
        InitializeComponent();
    }

    private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        this.DragMove();
    }
}
飞溅xaml

<Window x:Class="SplashScreenWPF.Splash"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:SplashScreenWPF"
    mc:Ignorable="d"
    Title="Splash" Height="300" Width="300" MouseLeftButtonDown="Window_MouseLeftButtonDown">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="147*"/>
        <ColumnDefinition Width="145*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="135*"/>
        <RowDefinition Height="134*"/>
    </Grid.RowDefinitions>
    <Button  Margin="30" Grid.Column="0" />
    <Button  Margin="30" Grid.Column="2" />
    <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="30,66,0,0" Grid.Row="1" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
    <ProgressBar x:Name="ProgressBar" Grid.Column="1" HorizontalAlignment="Left" Height="16" Margin="24,66,0,0" Grid.Row="1" VerticalAlignment="Top" Width="100"/>

</Grid>


鼠标悬停发生在GUI线程中,按钮逻辑在另一个线程中;解决这个问题,您就会解决问题。什么是
Dispatcher.Run()
?只需使用
ShowDialog()
而不是
Show()
,线程将不会继续运行,直到窗口关闭。如果您试图创建线程安全的启动屏幕,那么您会失败。当您注释掉
ApartmentState.STA
行时会发生什么?同样的行为会发生吗?@O