从另一个类和单独的线程更改WPF主窗口标签

时间:2013-03-15 05:37:35

标签: wpf dispatcher mainwindow

我正在研究WPF应用程序。我在MainWindow.xaml中有一个名为“Status_label”的标签。我想从不同的类(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(() =>{..........或其他内容解决此问题吗?

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

MainWindow.xaml

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

SignIn.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.

请指导我,

谢谢

5 个答案:

答案 0 :(得分:23)

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

在我的 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";

这对我来说很好。 您可以在此处找到更多详细信息,Change WPF window label content from another class and separate thread

欢呼声!!

答案 1 :(得分:2)

尝试以下代码段:

status_lable.Dispatcher.Invoke(...)

答案 2 :(得分:2)

感谢答案,他们引导我朝着正确的方向前进。我最终得到了这个简单的解决方案:

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

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

然后在另一个运行在不同thred中的类的eventhandler中:

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

这是为了显示通过namedPipeline收到消息时的最小化窗口。

答案 3 :(得分:1)

谢谢!我的解决方案略有不同,但你肯定用正确的方向指出了我的答案。

对于我的应用程序,我在main中有很多控件,而main上的大多数方法调用都是在main的范围内进行的,因此使用默认的{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,所以这对我来说更简单,但你的方法似乎同样有效。再次感谢!

答案 4 :(得分: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.
    }
}
相关问题