Wpf Ошибка при попытке добавить кнопку в WrapPanel - PullRequest
0 голосов
/ 16 сентября 2018

У меня есть FileSystemWatcher, который, конечно, проверяет папку на наличие изменений.Поэтому, когда вы добавляете файл в папку, мне нужно добавить кнопку в оболочку.Я попытался:

    public void CheckDir()
{
    string[] args = System.Environment.GetCommandLineArgs();
    var folderName = $"{AppDomain.CurrentDomain.BaseDirectory}games";

    FileSystemWatcher watcher = new FileSystemWatcher
    {
        Path = folderName,

        NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
       | NotifyFilters.FileName | NotifyFilters.DirectoryName
    };

    // Add event handlers.
    watcher.Changed += new FileSystemEventHandler(OnChanged);
    watcher.Created += new FileSystemEventHandler(OnChanged);
    watcher.Deleted += new FileSystemEventHandler(OnChanged);
    watcher.Renamed += new RenamedEventHandler(OnRenamed);

    // Begin watching.
    watcher.EnableRaisingEvents = true;

}

//When button is changed, created, or deleted
private void OnChanged(object source, FileSystemEventArgs e)
{
    Console.WriteLine("File: " + e.Name + " " + e.ChangeType);

    var buttonName = "Button_" + Path.GetFileNameWithoutExtension(e.FullPath).Replace(" ", "");

    if (e.ChangeType == WatcherChangeTypes.Created)
    {
        var buttonContent = Path.GetFileNameWithoutExtension(e.FullPath);

        CreateButton(buttonContent, buttonName);
    }
    else if (e.ChangeType == WatcherChangeTypes.Deleted)
    {

        buttonHolder.Children.Remove(btnFile);
    }
}

И пустота CreateButton:

private void CreateButton(string buttonContent, string buttonName)
{
    Button newBtn = new Button
    {
        Content = buttonContent,
        Name = buttonName,
        BorderThickness = new Thickness(1),
        Width = 260,
        Height = 100
    };

    newBtn.Click += OpenFile;

    buttonHolder.Children.Add(newBtn);
}

Но я получаю ошибку при попытке добавить кнопку:

Вызывающийпоток должен быть STA, потому что многие компоненты пользовательского интерфейса требуют этого.

И я не знаю, что изменить или что означает ошибка, и да, я искал ее, но не смог найтирешение или хорошее объяснение, что это такое.

1 Ответ

0 голосов
/ 17 сентября 2018

Позвольте мне попытаться объяснить вам это исключение.

Сначала я попытаюсь объяснить, что такое фоновый поток и поток пользовательского интерфейса и чем они отличаются, а затем два моих простых правила, которым нужно следовать при работе с этим исключением.

Мое объяснение STA и MTA, потоков пользовательского интерфейса и фоновых потоков

STA означает Single Thread Apartment, и у него есть аналог, называемый Multi Thread Apartment (MTA).И их различия обсуждаются в этом ответе , и вы можете использовать STA vs. MTA в качестве ключевых слов для поиска в Google, если вы заинтересованы.Вы можете быть озадачены, когда увидите в поиске такие термины, как «STAThreadAttribute» / «COM» / «CoInitializeEx», не беспокойтесь, потому что вы не одиноки, это несколько сумасшедших старых технологий, с которыми мало кто работает.

И поток использует одну из этих моделей, STA или MTA.Вы могли заметить, что некоторый код, такой как

[STAThread]
static void Main()

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

И фоновые потоки , которые вы начали использовать с классами вроде Thread/ThreadPool/Task, по умолчанию используют MTA, это также относится к обработчику событий System.Timers.Timer.Elapsed, и, как вв этом случае обработчик событий FileSystemWatcher events.

Теперь у вас есть идея, что ваш код работает либо на потоке пользовательского интерфейса (STA) , либо на одном из фоновых потоков(MTA) .

Мои простые правила

  1. Обычно необходимо создавать элементы управления в потоке пользовательского интерфейса .(Я не обсуждаю альтернативное решение «создания в фоновом потоке и его замораживания» здесь, просто чтобы соблюдать простые правила. И, как указано в комментарии @slugster, вы можете создать элемент управления на любой поток , но вы можете получить к нему доступ только из того же потока, в котором он был создан.)

  2. Из фонового потока , если вы хотите получить к нему доступэлементы управления, вам нужно перенаправить ваш код в поток пользовательского интерфейса с помощью Dispatcher.Invoke/BeginInvoke - чтобы код выполнялся в потоке пользовательского интерфейса.В противном случае вы получите это исключение (The calling thread must be STA...).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...