8

我正在开发一个 WPF 应用程序。我有一个名为“Status_label”的标签MainWindow.xaml。我想从不同的类(signIn.cs)更改它的内容。通常我可以做到这一点

var mainWin = Application.Current.Windows.Cast<Window>().FirstOrDefault(window => window is MainWindow) as MainWindow;
mainWin.status_lable.Content = "Irantha signed in";

但我的问题是,当我尝试通过 signIn.cs 类中的不同线程访问它时,它给出了一个错误:

The calling thread cannot access this object because a different thread owns it.

我可以通过使用Dispatcher.Invoke(new Action(() =>{..........或其他方式解决这个问题吗?

编辑: 我将从不同的类以及单独的线程中调用此标签更改操作

主窗口.xaml

<Label HorizontalAlignment="Left" Margin="14,312,0,0" Name="status_lable" Width="361"/>

登录.cs

    internal void getStudentAttendence()
    {
        Thread captureFingerPrints = new Thread(startCapturing);
        captureFingerPrints.Start();
    }

void mySeparateThreadMethod()
{
    var mainWin = Application.Current.Windows.Cast<Window>().FirstOrDefault(window => window is MainWindow) as MainWindow;
    mainWin.status_lable.Dispatcher.Invoke(new Action(()=> mainWin.status_lable.Content ="Irantha signed in"));
}

line var mainWin 返回错误The calling thread cannot access this object because a different thread owns it.

请指导我,

谢谢

4

5 回答 5

25

我解决了我的问题,希望有人需要这个。但不知道这是否是优化的方式。

在我的mainWindow.xaml.cs中:

    public  MainWindow()
    {
      main = this;
    }

    internal static MainWindow main;
    internal string Status
    {
        get { return status_lable.Content.ToString(); }
        set { Dispatcher.Invoke(new Action(() => { status_lable.Content = value; })); }
    }

来自我的SignIn.cs课程

 MainWindow.main.Status = "Irantha has signed in successfully";

这对我来说很好。您可以从此处找到更多详细信息,从另一个类和单独的线程更改 WPF 窗口标签内容

干杯!!

于 2013-03-28T06:40:06.063 回答
2

试试下面的片段:

status_lable.Dispatcher.Invoke(...)
于 2013-03-15T07:14:17.393 回答
2

多亏了答案,他们把我引向了正确的方向。我最终得到了这个简单的解决方案:

public partial class MainWindow : Window
{
    public static MainWindow main;

    public MainWindow()
    {
        InitializeComponent();                        
        main = this;
    }
}

然后在我的事件处理程序中运行在另一个线程中的另一个类中:

internal static void pipeServer_MessageReceived(object sender, MessageReceivedEventArgs e)
    {
        MainWindow.main.Dispatcher.Invoke(new Action(delegate()
        {
            MainWindow.main.WindowState = WindowState.Normal;
        }));
    }

当通过命名管道接收到我的消息时,这会显示最小化的窗口。

于 2015-08-07T09:07:49.943 回答
1

谢谢!我最终得到了一个略有不同的解决方案,但您的回答肯定为我指明了正确的方向。

对于我的应用程序,我在 main 中有很多控件,并且 main 上的大多数方法调用都发生在 main 范围内,因此使用 default { get; 更简单。在 MainWindow.xaml.cs 中设置 }(或仅在 XAML 中定义控件)。

在我的父窗口的代码隐藏中,我在这样的单独线程中启动 MainWindow(简化示例)。关键是全局定义 main,即使它是在 Window_Loaded() 内部实例化的:

    public ParentWindow()
    {
        InitializeComponent();
    }

    MainWindow main;

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        Thread otherThread = new Thread(() =>
        {
            main = new MainWindow();
            main.Show();

            main.Closed += (sender2, e2) =>
                main.Dispatcher.InvokeShutdown();

            System.Windows.Threading.Dispatcher.Run();
        });

        otherThread.SetApartmentState(ApartmentState.STA);
        otherThread.Start();

    }

然后在我的 MainWindow 代码隐藏中,我只是与控件交互,就好像它是一个简单的单线程应用程序一样(在我的情况下,子线程没有对父线程的控制)。但是,我可以像这样从父线程控制 main:

private void button_Click(object sender, RoutedEventArgs e)
        {
            main.Dispatcher.Invoke(new Action(delegate () 
                {
                    main.myControl.myMethod(); 
                }));

        }

通过这样做,我避免了在代码隐藏中定义所有内容以及在 MainWindow.xaml.cs 的代码隐藏中使用调度程序的复杂性。我的应用程序中只有几个地方可以从父窗口修改 main ,所以这对我来说更简单,但你的方法似乎同样有效。再次感谢!

于 2015-01-06T16:25:57.197 回答
0

没有使用的简单技巧Dispatcher.Invoke:在你的Window课堂上放这个:

public partial class MyWindow: Window
{
    public static MyWindow mywin;
    [...]

    public MyWindow()
    {
        InitializeComponent();
        mywin = this;
        [...]
    }

    [...]
}

接下来在您的第二堂课中调用您需要添加您的窗口名称+您分配的标签的属性。这是一个例子:

internal class MySecondClass
{
    internal void ChangeAValue()
    {
        MyWindow.mywin.ATextBox.Text = "Some text"; // I'm changing for example the text for a textbox in MyWindow.
    }
}
于 2020-04-26T18:23:41.783 回答