Изменение метки WPF mainwindow из другого класса и отдельного потока

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

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: Я назову это лейблом change 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"));
}

ошибка возврата строки var mainWinThe calling thread cannot access this object because a different thread owns it.

пожалуйста, руководство мне,

спасибо

4 ответов


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

в своем главное окно.код 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";

это отлично работает для меня. Вы можете найти более подробную информацию здесь изменить содержимое метки окна WPF из другого класса и отдельного потока

ура!!


попробовать ниже фрагмент:

status_lable.Dispatcher.Invoke(...)

Спасибо за ответы, они привели меня в правильном направлении. Я закончил с этим простым решением:

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.


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

для моего приложения у меня много элементов управления в main, и большинство вызовов метода main происходили из области main, поэтому было проще использовать значение по умолчанию { get; set } в 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.цезий. В моем приложении есть только несколько мест, где я изменяю main из родительского окна, поэтому для меня это было проще, но ваш подход кажется одинаково правильным. Еще раз спасибо!