powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Не удается организовать новый поток
6 сообщений из 6, страница 1 из 1
Не удается организовать новый поток
    #39559397
orac0ol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день. У меня есть класс для работы с файлами. В какой-то момент я заполняю коллекцию данными файлов из указанной директории.
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
public class PhotoCollection : ObservableCollection<Photo>
{
        public PhotoCollection() { }

        public PhotoCollection(string path) : this(new DirectoryInfo(path)) { }

        public PhotoCollection(DirectoryInfo directory)
        {
            _directory = directory;
            Update();
        }

        public string Path
        {
            set
            {
                _directory = new DirectoryInfo(value);
                Update();
            }
            get { return _directory.FullName; }
        }

        private void Update()
        {
            this.Clear();
            try
            {
                int cnt = 0;
                foreach (FileInfo f in _directory.GetFiles("*.jpg"))
                {
                    Add(new Photo(f.FullName, cnt));
                    cnt++;
                }

            }
            catch (DirectoryNotFoundException)
            {
                MessageBox.Show("Указанная директория не найдена!", "", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        DirectoryInfo _directory;
}



Хотелось бы вынести заполнение в новый поток. Но при попытке сделать так внутри класса:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
private void LoadFiles()
{
     int cnt = 0;
     foreach (FileInfo f in _directory.GetFiles("*.jpg"))
     {
           Add(new Photo(f.FullName, cnt));
           cnt++;
           Thread.Sleep(0);
     }
}

Thread myThread = new Thread(LoadFiles); //Создаем новый объект потока (Thread)
myThread.Start(); //запускаем поток
myThread.Join();



Вылетает исключение: "Данный тип CollectionView не поддерживает изменения в своем SourceCollection из потока, отличного от потока Dispatcher." Почитал, что надо использовать Dispatcher.Invoke. Подскажите, пожалуйста, как правильно обернуть данный фрагмент кода Dispatcher.Invoke?
...
Рейтинг: 0 / 0
Не удается организовать новый поток
    #39559411
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
orac0olДобрый день. У меня есть класс для работы с файлами. В какой-то момент я заполняю коллекцию данными файлов из указанной директории.
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
public class PhotoCollection : ObservableCollection<Photo>
{
        public PhotoCollection() { }

        public PhotoCollection(string path) : this(new DirectoryInfo(path)) { }

        public PhotoCollection(DirectoryInfo directory)
        {
            _directory = directory;
            Update();
        }

        public string Path
        {
            set
            {
                _directory = new DirectoryInfo(value);
                Update();
            }
            get { return _directory.FullName; }
        }

        private void Update()
        {
            this.Clear();
            try
            {
                int cnt = 0;
                foreach (FileInfo f in _directory.GetFiles("*.jpg"))
                {
                    Add(new Photo(f.FullName, cnt));
                    cnt++;
                }

            }
            catch (DirectoryNotFoundException)
            {
                MessageBox.Show("Указанная директория не найдена!", "", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        DirectoryInfo _directory;
}




Хотелось бы вынести заполнение в новый поток. Но при попытке сделать так внутри класса:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
private void LoadFiles()
{
     int cnt = 0;
     foreach (FileInfo f in _directory.GetFiles("*.jpg"))
     {
           Add(new Photo(f.FullName, cnt));
           cnt++;
           Thread.Sleep(0);
     }
}

Thread myThread = new Thread(LoadFiles); //Создаем новый объект потока (Thread)
myThread.Start(); //запускаем поток
myThread.Join();




Вылетает исключение: "Данный тип CollectionView не поддерживает изменения в своем SourceCollection из потока, отличного от потока Dispatcher." Почитал, что надо использовать Dispatcher.Invoke. Подскажите, пожалуйста, как правильно обернуть данный фрагмент кода Dispatcher.Invoke?
самый просто путь, это в многопоточности грузить то, что вам надо в 1 коллекцию, не связанную с интерфейсом, либо каждый поток грузит свою коллекцию
в конце, когда все загрузилось объединить и вставить в основном потоке
...
Рейтинг: 0 / 0
Не удается организовать новый поток
    #39559428
orac0ol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Roman Mejtes, а не могли бы вы привести хотя бы обобщенный вариант вашего решения касательно моего случая? Просто не совсем понятно, что вы имели в виду
...
Рейтинг: 0 / 0
Не удается организовать новый поток
    #39559988
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
orac0olХотелось бы вынести заполнение в новый поток.
Цель?
...
Рейтинг: 0 / 0
Не удается организовать новый поток
    #39560034
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
orac0ol,
Invoke это 26 мкс на вызов.
Т.е. если на каждое фото, то может тормозить. А может и нет.
Лучше показывай штук 300 маленьких.
Ищи компроиисс.
...
Рейтинг: 0 / 0
Не удается организовать новый поток
    #39560047
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
в данный момент я вижу, что у вас метод просто читает названия файлов в коллекцию.
Данная операция, если там не 100500 файлов выполняется очень быстро, на столько, что делать это в отдельном потоке не имеет смысла.
А вообще переходите на async\await и Task'и из TPL
Но вот вам пример, для затравки (это только пример, многие классы тут написаны на коленке за пару минут):
Данный пример не претендует на Best Practics.
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;

namespace MultiThreadingExample
{

    public class ActionAsyncCommand : ICommand
    {
        private Func<object, Task> _execute;

        public ActionAsyncCommand(Func<object, Task> execute)
        {
            _execute = execute;
        }

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }

    public class ActionCommand : ICommand
    {
        private Action<object> _execute;

        public ActionCommand(Action<object> execute)
        {
            _execute = execute;
        }

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }

    public class FileModel
    {
        public FileModel(FileInfo fileInfo)
        {
            Name = fileInfo.Name;
            Path = fileInfo.FullName;
            Size = fileInfo.Length;
        }

        public string Name { get; }
        public string Path { get; }
        public long Size { get; }
    }

    public class MainModel
    {
        public MainModel()
        {
            Files = new ObservableCollection<FileModel>();
        }

        public ObservableCollection<FileModel> Files { get; }

        private ICommand _loadFilesAsync;
        public ICommand LoadFilesAsync => _loadFilesAsync ?? (_loadFilesAsync = new ActionAsyncCommand(OnLoadFilesAsync));

        private ICommand _loadFilesSync;
        public ICommand LoadFilesSync => _loadFilesSync ?? (_loadFilesSync = new ActionCommand(OnLoadFilesSync));

        private void OnLoadFilesSync(object obj)
        {
            Files.Clear();
            var path = Environment.SystemDirectory;
            foreach (var fileModel in GetFilesModelsInternal(path))
            {
                Files.Add(fileModel);
            }
        }

        private async Task OnLoadFilesAsync(object obj)
        {
            Files.Clear();
            var filesModels = await OnGetFilesAsync(CancellationToken.None);
            foreach (var fileModel in filesModels)
            {
                Files.Add(fileModel);
            }
        }

        private Task<List<FileModel>> OnGetFilesAsync(CancellationToken token)
        {
            return Task.Run(() =>
            {
                var path = Environment.SystemDirectory;
                return GetFilesModelsInternal(path).ToList();
            }, token);
        }

        private IEnumerable<FileModel> GetFilesModelsInternal(string path, int max = 100)
        {
            int index = 0;
            foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.TopDirectoryOnly))
            {
                Task.Delay(5).Wait();
                var info = new FileInfo(file);
                var model = new FileModel(info);
                yield return model;
                if (++index > max) break;
            }
        }
    }
}


Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
<Window x:Class="MultiThreadingExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MultiThreadingExample"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainModel/>
    </Window.DataContext>
    <Window.Resources>
        <Style TargetType="{x:Type ProgressBar}">
            <Style.Triggers>
                <EventTrigger RoutedEvent="Loaded">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Value"
                                                 From="0" To="100" AutoReverse="True"
                                                 RepeatBehavior="Forever"
                                                 Duration="0:0:2" >
                                    <DoubleAnimation.EasingFunction>
                                        <PowerEase Power="0.5"/>
                                    </DoubleAnimation.EasingFunction>
                                </DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </Style.Triggers>
        </Style>
        <DataTemplate DataType="{x:Type local:FileModel}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding Name}" Margin="5,2"/>
                <TextBlock Grid.Column="1" Text="{Binding Size}" Margin="5,2"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ListBox Grid.Row="0" Margin="5" ItemsSource="{Binding Files}"/>
        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="5,0,5,5">
            <Button Content="Async Load" Command="{Binding LoadFilesAsync}" 
                    Padding="10,5" Margin="0,0,5,0"/>
            <Button Content="Sync Load" Command="{Binding LoadFilesSync}" 
                    Padding="10,5" Margin="0,0,5,0"/>
            <ProgressBar Maximum="100" Width="300"/>
        </StackPanel>
    </Grid>
</Window>



Так же, из другого потока можно вызвать код через Dispatcher.
Получить Dispatcher UI контекста можно через класс Application
Код: c#
1.
Application.Current.Dispatcher


Полностью, это будет выглядеть вот так:
Application.Current.Dispatcher.Invoke(() => Тут пишем код, который будет вызывать из основного потока, DispatcherPriority.Normal);
Приоритет определяет когда будет вызван метод, на каком этапе работы диспатчера.
После биндинга, после загрузки, когда приложение будет простаивать и т.д.

Почитай про то, что такое асинхронный\синхронный вызов, про многопоточность, TPL, async\await и что такое синхронизация в многопоточной среде, а потом приходите сюда с такими вопросами.
Пока не прочитаете, лучше делайте всё синхронно.
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Не удается организовать новый поток
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]