我正在研究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 return errorThe calling thread cannot access this object because a different thread owns it.
请指导我,
谢谢
我解决了我的问题,希望有人会需要这个。但不知道这是否是优化方式。
在我的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
干杯!!
尝试下面的代码段:
status_lable.Dispatcher.Invoke(...)
感谢答案,他们引导我朝着正确的方向前进。我最终得到了这个简单的解决方案:
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;
}));
}
这是为了显示通过namedPipeline接收消息时的最小化窗口。
谢谢!最后我找到了一个略有不同的解决方案,但你肯定用正确的方向指出了我的答案。
对于我的应用程序,我在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,所以这对我来说更简单,但你的方法似乎同样有效。再次感谢!