2013-03-15 2 views
7

Im работает над приложением WPF. У меня есть метка «Status_label» в MainWindow.xaml. и я хочу изменить его содержимое из другого класса (signIn.cs). Обычно я в состоянии сделать этоИзменение метки WPF mainwindow из другого класса и отдельной темы

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(() =>{.......... или что-то еще?

EDIT: Я позову это изменение этикетки действия от другого класса, как-хорошо, как отдельного поток

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 ине вар возвращение mainWin ошибка The calling thread cannot access this object because a different thread owns it.

Пожалуйста, наставит меня,

Спасибо

+0

Почему это проголосовало? – iJay

+0

Возможно, потому что на этот вопрос был дан ответный момент. Некоторые «googling» предоставят вам правильное решение. – DHN

ответ

22

Я решил мой вопрос, надеюсь, кто-то это нужно. Но не знаю, оптимизирован ли это.

В моих 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

Отлично! Большое спасибо! – MDDDC

2

попытка ниже фрагмент кода:

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

Спасибо за ответ. но моя проблема связана с разными темами. – iJay

+0

Не понимаю, что вы имеете в виду. Вы хотите сделать это в отдельной теме? Вы можете использовать status_lable.Dispatcher.BeginInvoke (...) или Task.Factory.StartNew (() => {status_lable.Dispatcher.BeginInvoke (...);}); если вы хотите быть более отзывчивым – David

+0

Но моя ошибка возвращается из строки var mainWin, могу ли я получить статус status_label в mainWindow по-другому? Я отредактировал вопрос, может ли вы проверить его? – iJay

1

Спасибо! Я закончил с немного иным решением, но вы определенно указали мне в правильном направлении с вашим ответом.

Для моего приложения у меня есть много элементов управления в основном, и большинство вызовов метода на основном происходили из области main, поэтому было проще использовать значение по умолчанию {get; set} внутри MainWindow.xaml.cs (или просто определить элементы управления в XAML).

В коде моего родительского окна я запускаю MainWindow в отдельном потоке, подобном этому (упрощенный пример).Ключ для определения основной во всем мире, несмотря на то, что конкретизируется внутри 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 кода позади, я просто взаимодействовать с элементами управления, как будто это простой однопоточных приложений (в моем случае нет контроля над родительским потоком от дочернего потока). Я могу, однако, управления основными из родительской нити, как это:

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

     } 

Делая это таким образом, избежать сложности определения все в коде-позади и с помощью диспетчера изнутри отделенного кода в MainWindow .xaml.cs. В моем приложении есть только несколько точек, где я изменяю main из родительского окна, поэтому для меня это было проще, но ваш подход кажется одинаковым. Еще раз спасибо!

2

Благодаря ответам они привели меня в правильном направлении. Я закончил с этим простым решением:

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

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

Тогда в моем EventHandler в другом классе, который работает в другом thred:

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

Это, чтобы показать свернутое окно, когда я сообщение получено через namedPipeline ,