2013-03-15 7 views
7

Ich arbeite an einer WPF-Anwendung. Ich habe ein Label namens "Status_label" in MainWindow.xaml. und ich möchte seinen Inhalt von einer anderen Klasse (signIn.cs) ändern. dieses Normalerweise Ändern Sie WPF Hauptfenster Label aus einer anderen Klasse und separaten Thread

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

Ich bin in der Lage zu tun, aber mein Problem ist, wenn ich versuche, es in signIn.cs Klasse über anderen Thread zuzugreifen, gibt es eine Fehlermeldung:

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

Kann ich das lösen, indem ich Dispatcher.Invoke(new Action(() =>{.......... oder etwas anderes benutze?

EDIT: Ich werde Anruf dieses Label ändert Aktion von anderer Klasse als-auch-als separater Thread

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")); 
} 

l ine var MainWin Rückkehr Fehler The calling thread cannot access this object because a different thread owns it.

Bitte leite mich,

Danke

+0

Warum wird dies abgelehnt? – iJay

+0

Vielleicht, weil diese Frage schon hundertmal beantwortet wurde. Etwas "googeln" würde Ihnen eine angemessene Lösung bieten. – DHN

Antwort

22

ich meine Frage gelöst, hoffe jemand wird dies benötigen. Aber weiß nicht, ob das der optimierte Weg ist.

In meinem 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; })); } 
    } 

von meiner SignIn.cs Klasse

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

Dies funktioniert gut für mich. Sie finden weitere Details von hier, Change WPF window label content from another class and separate thread

prost !!

+1

Großartig! Vielen Dank !!! – MDDDC

2

Versuch unter Schnipsel:

status_lable.Dispatcher.Invoke(...) 
+1

Danke für die Antwort. aber mein Problem ist aufgrund anderer Thread. – iJay

+0

Verstehen Sie nicht, was Sie meinen.Wollen Sie das in einem separaten Thread tun? Sie können status_lable.Dispatcher.BeginInvoke (...) oder verwenden. Task.Factory.StartNew (() => {status_lable.Dispatcher.BeginInvoke (...);}); Wenn Sie mehr Reponsive sein möchten – David

+0

Aber mein Fehler Rückkehr von var MainWin Linie, Kann ich mainWindow status_label auf andere Weise zugreifen? Ich habe die Frage bearbeitet können Sie es überprüfen? – iJay

1

Vielen Dank! Ich habe eine etwas andere Lösung gefunden, aber Sie haben mich mit Ihrer Antwort definitiv in die richtige Richtung gelenkt.

Für meine Anwendung habe ich viele Steuerelemente in main, und die meisten Methodenaufrufe auf main wurden im Rahmen von main ausgeführt, sodass es einfacher war, den Standardwert {get; } in MainWindow.xaml.cs festlegen (oder nur die Steuerelemente in XAML definieren).

Im Code-Behind des übergeordneten Fensters starte ich das MainWindow in einem separaten Thread wie diesem (vereinfachtes Beispiel).Der Schlüssel ist, Haupt global zu definieren, auch wenn es innerhalb von Window_Loaded instanziiert wird():

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(); 

    } 

Da ist in meinem Mainwindow Code-behind, ich habe gerade mit den Bedienelementen interagieren, als ob es sich um eine einfache Single-Threaded-Anwendung ist (In meinem Fall gibt es keine Kontrolle über den übergeordneten Thread aus dem untergeordneten Thread). Ich kann jedoch von dem übergeordneten Thread wie das Haupt steuern:

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

     } 

Durch es auf diese Weise tun, vermeide ich die Komplexität alles in der Definition von Code-Behind und mit dem Dispatcher aus dem Code-Behind von Mainwindow .xaml.cs. Es gibt nur ein paar Stellen in meiner Anwendung, wo ich main aus dem Elternfenster ändere, also war das einfacher für mich, aber Ihre Herangehensweise scheint genauso gültig zu sein. Danke noch einmal!

2

Dank der Antworten haben sie mich in die richtige Richtung geführt. Ich landete mit dieser einfachen Lösung:

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

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

Da ist in meinem Eventhandler in einer anderen Klasse, die in einem anderen thred läuft:

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

Dies das minimierte Fenster zu zeigen, wenn ich Nachricht über eine namedPipeline empfangen wird .