WPF: UnauthorizedAccessException с использованием анонимных методов - PullRequest
1 голос
/ 11 января 2011

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

private void button3_Click(object sender, RoutedEventArgs e)
{

    //progressBar1.Maximum = _FileInfoArray.Count;

    DispatcherTimer dt1 = new DispatcherTimer();
    foreach (FileInfo Fi in _FileInfoArray)
    {
        Thread t = new Thread(new ThreadStart(delegate()
        {
            DispatcherOperation _dispOp = progressBar1.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(delegate()
            {

                File.Copy(txtdestino.Text, Fi.FullName, true);

                //progressBar1.Value = n;
                //txtstatus.Content = ("Copiados " + n.ToString() + " archivos");
                //Thread.Sleep(100);
            }
            ));
            _dispOp.Completed += new EventHandler(_dispOp_Completed);
        }
            ));
        t.Start();
    }
}

UnauthorizedAccessException - throw!Это говорит о том, что я не могу получить доступ к контенту txtdestino.Некоторые подсказки?

------------------------------------------------------------------------------- Отредактировано Это версия со всеми изменениями, выдается та же ошибка:(какие-нибудь подсказки?

private void button4_Click(object sender, RoutedEventArgs e)
{
    //First: Build mynames
    List<string> mynames = new List<string>();
    foreach (FileInfo fi in _FileInfoArray)
    {
        mynames.Add(fi.FullName);
    }



    Thread t = new Thread(new ThreadStart(delegate()
       {
          foreach (string fullname in mynames)
            {
            DispatcherOperation _dispOp = progressBar1.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(delegate()
            {
                string destino = System.IO.Path.Combine(@"C:\", System.IO.Path.GetFileName(fullname));
                File.Copy(fullname, destino, true);
                //Some progressbar changes
            }
            ));
            _dispOp.Completed += new EventHandler(_dispOp_Completed);
          }
        }
                ));
        t.Start();
    }

File.Copy (txtdestino.Text, Fi.FullName, true); // здесь исключение throw

Ответы [ 3 ]

2 голосов
/ 11 января 2011

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

string txt = txtdestino.Text;
foreach (FileInfo Fi in _FileInfoArray)
{
    ....
    File.Copy(txt, Fi.FullName, true);
1 голос
/ 11 января 2011

Вы создаете несколько потоков (по 1 на каждый найденный файл).
Проблема в том, что только ваш основной поток может получить доступ к вашим элементам формы, иначе все потоки будут изменять элементы формы одновременно.

Передайте значение txtdestino.Text новой теме, и все будет в порядке.

1 голос
/ 11 января 2011

Если несколько потоков пытаются получить доступ (одновременно) к файлу на txtdestino.Text - разве это не обречено с самого начала? Возможно, вы захотите прочитать содержимое в память сначала и записать оттуда ...

Точно так же вы собираетесь забить IO; Интересно, может ли более практичный ответ (который решает проблему выше и ниже) просто скопировать последовательно на работника.

Похоже, что вы действительно возвращаете всю работу обратно в поток пользовательского интерфейса в любом случае ...? конечно, вы должны сделать что-то вроде:

string path = txtdestino.Text;
Thread t = new Thread(new ThreadStart(delegate() {
    foreach (FileInfo Fi in _FileInfoArray) {
        File.Copy(path, Fi.FullName, true);
    }
}));
t.Start();

, который:

  • позволяет избежать проблемы foreach / capture (Fi не фиксируется)
  • читает путь из потока пользовательского интерфейса и использует его (захваченный) на рабочем
  • обрабатывайте каждый файл последовательно, чтобы избежать ввода-вывода

У вас также есть проблема foreach / capture; измените его на:

foreach (FileInfo tmp in _FileInfoArray)
{
    FileInfo Fi = tmp;
    ...

Проблема в том, что, скорее всего, все потоки пытаются получить доступ к файлу last . Нет, правда. Это потому, что технически foreach объявляет переменную (tmp выше) вне цикла; и правила захвата переменных (используемые lambdas / anon-методами) говорят, что, следовательно, это то же самое переменная (важно: lambdas / anon-методы являются полными лексическими замыканиями, и захватывает переменную * 1045) *, а не значение ).

Повторное объявление переменной внутри цикл изменяет область, и теперь lambda / anon-метод обрабатывает переменную как другую для каждой итерации цикла.

Если вы действительно хотите, я мог бы записать это во что-то, что показывает задействованные базовые объекты, но это зависит от того, хотите ли вы этого уровня детализации; p

...