为什么线程只运行一次 - 打开和关闭窗口?

Why does the thread run only once - open and close windows?

提问人:McStar 提问时间:11/16/2023 更新时间:11/20/2023 访问量:54

问:

我正在尝试在登录程序时打开“加载”窗口。一切只正常工作一次。第二次运行它时,出现错误:System.InvalidOperationException:调用线程无法访问此对象,因为它属于另一个线程。请帮忙...

视图模型 .cs

private ProszeCzekaj proszeCzekaj;

private async void ZalogujExecute(object obj)
{
    try
    {

        Thread tbr = new Thread(() =>
        {
            proszeCzekaj = new ProszeCzekaj();
            proszeCzekaj.Closed += (sender2, e2) =>
                proszeCzekaj.Dispatcher.InvokeShutdown();
            proszeCzekaj.Show();
            Dispatcher.Run();
        });
        tbr.SetApartmentState(ApartmentState.STA);  //required for WPF
        tbr.Start();

        var odp = await SprawdzLogowanie();
        if (odp==1)
        {
            
        }
        proszeCzekaj.Dispatcher.Invoke(proszeCzekaj.Window2Close);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

async Task<int> SprawdzLogowanie()
{
    await Task.Run(() =>
    {
        AplikacjaDbContext db = new AplikacjaDbContext();
        foreach (var user in db.UsersTable.ToList())
        {
            MessageBox.Show(user.userLogin); //for test
        }
    });
    
    return 1;
}

Logowanie.xaml.cs

namespace PGSQL.View
{
    /// <summary>
    /// Logika interakcji dla klasy Logowanie.xaml
    /// </summary>
    public delegate void dWindow2Close();
    public partial class Logowanie : Window
    {
        public Logowanie()
        {
            InitializeComponent();

            LogowanieViewModel model = new LogowanieViewModel();
            this.DataContext = model;
        }
    }
}

加载.xaml.cs

namespace PGSQL.View
{
    /// <summary>
    /// Logika interakcji dla klasy ProszeCzekaj.xaml
    /// </summary>
    public partial class ProszeCzekaj : Window
    {
        public dWindow2Close Window2Close;

        public ProszeCzekaj()
        {
            InitializeComponent();
            Window2Close = new dWindow2Close(SecondWindowClose);

            IntPtr hWnd = new WindowInteropHelper(GetWindow(this)).EnsureHandle();
            var attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE;
            var preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND;
            DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint));

            ProszeCzekajViewModel model = new ProszeCzekajViewModel();
            this.DataContext = model;
        }

        private void SecondWindowClose()
        {
            this.Close();
        }

        public enum DWMWINDOWATTRIBUTE
        {
            DWMWA_WINDOW_CORNER_PREFERENCE = 33
        }

        // The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, which tells the function
        // what value of the enum to set.
        // Copied from dwmapi.h
        public enum DWM_WINDOW_CORNER_PREFERENCE
        {
            DWMWCP_DEFAULT = 0,
            DWMWCP_DONOTROUND = 1,
            DWMWCP_ROUND = 2,
            DWMWCP_ROUNDSMALL = 3
        }

        // Import dwmapi.dll and define DwmSetWindowAttribute in C# corresponding to the native function.
        [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
        internal static extern void DwmSetWindowAttribute(IntPtr hwnd,
                                                         DWMWINDOWATTRIBUTE attribute,
                                                         ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute,
                                                         uint cbAttribute);
    }
}
C# 多线程 XAML 任务

评论

0赞 Renat 11/16/2023
如下: stackoverflow.com/questions/1111369/...,可能需要添加(之前),但我只是猜测tbr.IsBackground = true;tbr.Start();
1赞 McStar 11/16/2023
感谢您的回答,不幸的是仍然是同样的错误。Visual Studio 在 ViewModel.cs 中完全选择此行 - - 作为导致错误的行proszeCzekaj.Show();
0赞 Stephen Cleary 11/16/2023
请发布异常堆栈跟踪和调用 .另外,您所说的“秒”是指一个完全独立的应用程序实例,还是在同一应用程序中调用两次此代码?ZalogujExecute
0赞 McStar 11/17/2023
我不确定我是否 100% 正确理解了您的请求,但是......调用卡住并编码 . 是 XAML 中按钮上的绑定命令。在 ViewModel 和> PGSQL.exe!PGSQL::ViewModel::LogowanieViewModel::<<ZalogujExecute>b__33_0>d::MoveNext()proszeCzekaj.Show();ZalogujExecutepublic PGSQLCommand Zaloguj { get; set; }Zaloguj = new PGSQLCommand(ZalogujExecute, ZalogujCanExecute);
0赞 McStar 11/17/2023
作为测试,我用以下代码替换了 Logowanie.cs::-(同样的错误private void Zaloguj_Click(object sender, RoutedEventArgs e) { Thread tbr = new Thread(() => { br = new ProszeCzekaj(); br.Closed += (sender2, e2) => br.Dispatcher.InvokeShutdown(); br.Show(); System.Windows.Threading.Dispatcher.Run(); }); tbr.SetApartmentState(ApartmentState.STA); //required for WPF tbr.Start(); } private void Anuluj_Click(object sender, RoutedEventArgs e) { br.Dispatcher.Invoke(br.Window2Close); }

答:

0赞 SmellyCat 11/20/2023 #1

如果重用 Show 方法,预计会引发异常。

在正在关闭 (Closesing) 或已关闭 (Closed) 的窗口上调用 InvalidOperationException
Show()。

如果要重用窗口,最好:

  • 调用隐藏而不是SecondWindowCloseClose
  • 为了防止用户关闭,也许使用 WindowStyleProszeCzekaj