Как мне обновить свой интерфейс без заиканий / тупиков - PullRequest
0 голосов
/ 17 мая 2019

У меня есть приложение WPF, которое имеет DataGrid, которое привязано к ObservableCollection<string> с именем «Клиенты» , и у меня также есть кнопка, которая связана с командой, которая запускает что-тотяжелая задачаон имитирует добавление нескольких записей в DataGrid как можно быстрее.

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

Насколько я понимаю, это потому, что я обновляю DataGrid в потоке пользовательского интерфейса, используя Application.Current.Dispatcher.Invoke(() => { /*Update OC*/ });, и даже если они могут быть маленькимиобновляет пользовательский интерфейс, многие из них могут вызвать заикание, теперь это мое понимание, и я могу быть совершенно не прав.

Мой вопрос ... Есть ли способ сделать этот асинхронный или уменьшить заикание/ deadlocks каким-либо другим способом?

Пользовательский интерфейс XAML

<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>

<Grid>
    <StackPanel>
        <DataGrid ItemsSource="{Binding Customers}" AutoGenerateColumns="False" 
                  Width="300" Height="200">
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Image" Width="SizeToCells" IsReadOnly="True">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding }" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
        <Button Width="100"
                Height="25"
                Content="Start"
                Command="{Binding StartAddingCommand}"/>
    </StackPanel>

    <Border VerticalAlignment="Bottom"
            Height="25" Background="Orange">
        <TextBlock Text="{Binding Customers.Count}"
                   HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Border>
</Grid>

MainViewModel

class MainViewModel : ObservableObject
    {
        public ObservableCollection<string> Customers { get; set; }
        public RelayCommand StartAddingCommand { get; set; }
        public MainViewModel()
        {
            Customers = new ObservableCollection<string>();
            StartAddingCommand = new RelayCommand(o => AddCustomers(), o => true);
        }


        private void AddCustomers()
        {
            Task.Run(() =>
            {
                try
                {
                    foreach (var VARIABLE in GetHTML("https://pastebin.com/raw/gG540TEj"))
                    {
                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            Customers.Add(VARIABLE.ToString());
                        });
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }

            });

        }


        public string GetHTML(string page)
        {
            WebClient client = new WebClient();
            return client.DownloadString(page);
        }
    }

А RelayCommand & ObservableObject являются просто общими.

RelayCommand

public class RelayCommand : ICommand
    {
        private Action<object> execute;
        private Func<object, bool> canExecute;

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return this.canExecute == null || this.canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            this.execute(parameter);
        }
    }

ObservableObject

class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

1 Ответ

0 голосов
/ 17 мая 2019

Выполнение foreach с Dispatcher.Invoke без каких-либо задержек, конечно, заблокирует пользовательский интерфейс.

Вы обязательно должны иметь async версию вашего GetHTML метода и написать AddCustomers, как показано ниже. Используйте, например, один из Get...Async методов класса HttpClient.

private async Task AddCustomers()
{
    try
    {
        foreach (var result in await GetHTMLAsync("https://pastebin.com/raw/gG540TEj"))
        {
            Customers.Add(result.ToString());
        }
     }
     catch (Exception e)
     {
         Debug.WriteLine(e);
         throw;
     }
}

Затем дождитесь метода в командном действии:

StartAddingCommand = new RelayCommand(async o => await AddCustomers(), o => true);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...