2013-03-15 12 views
7

Im pracuje nad aplikacją WPF. Mam etykietę "Status_label" w MainWindow.xaml. i chcę zmienić jego zawartość z innej klasy (signIn.cs). Normalnie jestem w stanie to zrobićZmiana etykiety głównego okna głównego WPF z innej klasy i osobnego wątku

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

Ale mój problem jest, gdy próbuję uzyskać do niego dostęp za pośrednictwem innego wątku w klasie signIn.cs, daje błąd:

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

Czy mogę rozwiązać ten problem, używając Dispatcher.Invoke(new Action(() =>{.......... lub czegoś innego?

EDIT: Zadzwonię akcja ta zmiana etykiety z innej klasy jak-dobrze jako oddzielny wątek

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 błąd powrót mainWin The calling thread cannot access this object because a different thread owns it.

proszę kierować do mnie,

Dziękuję

+0

Dlaczego to nie jest głosowanie? – iJay

+0

Być może dlatego, że na to pytanie odpowiedziano na kilka godzin. Niektóre "googlowanie" zapewniłoby odpowiednie rozwiązanie. – DHN

Odpowiedz

22

postanowiłem moje pytanie, mam nadzieję, że ktoś będzie tego potrzebować. Ale nie wiem, czy to zoptymalizowany sposób.

W moich 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; })); } 
    } 

z moich SignIn.cs klasa

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

Działa to dobrze dla mnie. Możesz znaleźć więcej informacji tutaj, Change WPF window label content from another class and separate thread

Pozdrawiam!

+1

Świetnie! Wielkie dzięki! – MDDDC

2

try poniżej fragmencie:

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

Dzięki za odpowiedź. ale mój problem wynika z innego wątku. – iJay

+0

Nie rozumiesz, co masz na myśli. Czy chcesz to zrobić w osobnym wątku? Możesz użyć status_lable.Dispatcher.BeginInvoke (...) lub Task.Factory.StartNew (() => {status_lable.Dispatcher.BeginInvoke (...);}); jeśli chcesz być bardziej reponutywny – David

+0

Ale mój błąd wraca z var mainWin linii, Czy mogę uzyskać dostęp do main_index na statusie mainWindow w inny sposób? Edytowałem pytanie, czy możesz to sprawdzić? – iJay

1

Dziękujemy! Kończyłem nieco inne rozwiązanie, ale zdecydowanie wskazałeś mi właściwą odpowiedź.

Dla mojej aplikacji, mam dużo kontroli w głównej, a większość wywołań metod na main występowało z zakresu głównego, więc łatwiej było użyć domyślnego {get; ustaw} wewnątrz MainWindow.xaml.cs (lub po prostu zdefiniuj formanty w XAML).

W oknie z moim nadrzędnym oknem uruchamiam MainWindow w osobnym wątku w ten sposób (uproszczony przykład).Kluczem jest określenie głównego całym świecie, mimo że jest tworzony wewnątrz 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(); 

    } 

Wtedy w moim MainWindow kod z opóźnieniem, po prostu interakcję z kontroli, jakby to proste jednowątkowy aplikacja (W moim przypadku nie ma kontroli nad wątkiem nadrzędnym z wątku potomnego). Mogę jednak kontrolować główne z nici macierzystej jak ten:

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

     } 

robiąc to w ten sposób uniknąć złożoności definiowania wszystkiego w kodzie opóźnieniem i przy użyciu dyspozytora z poziomu kodu źródłowego z MainWindow .xaml.cs. W mojej aplikacji jest tylko kilka miejsc, w których modyfikuję główne z okna nadrzędnego, więc było to dla mnie prostsze, ale twoje podejście wydaje się równie ważne. Dzięki jeszcze raz!

2

Dzięki odpowiedziom poprowadzili mnie we właściwym kierunku. Skończyło się to proste rozwiązanie:

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

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

Wtedy w moim eventhandler w innej klasy, która biegnie w innym thred:

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

to, aby pokazać zminimalizowane okna po odebraniu i wiadomość poprzez namedPipeline .

Powiązane problemy