D-Kishore Ответов: 3

Как пользоваться диспетчером в MVVM в WPF привязка элементов в ComboBox


Привет,

Я внедряю одно приложение в WPF MVVM.

Я WPF-приложения и библиотеки DLL класса.

Например в приложении у меня есть 2 combobox х

Я привязываю серверы баз данных к 1-му combobox.

основываясь на выборе 1-го combobox, я связываю 2-й combobox со списком всех баз данных.

моя проблема заключается в том, что когда мы выбираем сервер из 1 - го выпадающего списка, он сохраняет открытое состояние, и приложение некоторое время зависает. Я не могу делать другие операции в это конкретное время.

Мой код XAML ниже :
<ComboBox Grid.Column="2" 
                  Grid.Row="1" Grid.ColumnSpan="3" MaxHeight="25" 
                  ItemsSource="{Binding Servers}"  
                  SelectedValue="{Binding SelectedServer}"
                  Name="cboServer" 
                  DataContext="{Binding Source={StaticResource vm}}" />

<ComboBox Grid.Column="2" 
             Grid.Row="2" Grid.ColumnSpan="3" MaxHeight="25" 
             ItemsSource="{Binding Databases}"
             SelectedValue="{Binding SelectedDatabase}"
             Name="cboDatabase" 
             DataContext="{Binding Source={StaticResource vm}}"/>

Мой код модели представления выглядит следующим образом:
/// <summary>
        /// For Servers Properties
        /// </summary>
        private ObservableCollection<string> _Servers;         
        private string _SelectedServer;
        public ObservableCollection<string> Servers        
        {
            get { return _Servers; }
            set
            {
                _Servers = value;
                OnPropertyChanged("Servers");
            }
        }
        public string SelectedServer
        {
            get { return _SelectedServer; }
            set
            {
               _SelectedServer = value;
                OnPropertyChanged("SelectedServer");

_extractInfo.ServerName = !string.IsNullOrEmpty(_SelectedServer) ? _SelectedServer : null;
         if (!string.IsNullOrEmpty(_extractInfo.ServerName))
              GetDatabases();
           else
              Databases = new ObservableCollection<string>();

}
}

         /// <summary>
        /// For Databases 
        /// </summary>
        private ObservableCollection<string> _DataBaseList; 
        private string _SelectedDatabase;
        public ObservableCollection<string> Databases         
        {
            get { return _DataBaseList; }
            set
            {
                _DataBaseList = value;
                           
                OnPropertyChanged("Databases");
            }
        }

//calling function GetDatabases(): ExtractHelper is located in my DAL Project
private ObservableCollection<string> GetDatabases()
        {
           try
            {
               
             Databases = new ObservableCollection<string>(ExtractHelper.RequestList(_extractInfo, ExtractHelper.RequestTypes.Databases).AsEnumerable().Select(x => x.DatabaseName));
                
                return Databases;
            }
            catch(Exception ex)
            { 
                MessageBox.Show(ex.Message);
            }
            return null;
        }

Пожалуйста, дайте мне знать, есть ли что-то не так с кодом, если это неправильно, дайте мне знать, как мы достигаем без замораживания приложения

Что я уже пробовал:

Я пробовал использовать диспетчер, как показано ниже.
Когда я использую приведенный ниже код, 1-й combobox закрывается, когда я выбираю сервер, но приложение некоторое время зависает, а затем отображает список баз данных во 2-м combobox.
public string SelectedServer
        {
            get { return _SelectedServer; }
            set
            {
               _SelectedServer = value;
                OnPropertyChanged("SelectedServer");

                _extractInfo.ServerName = !string.IsNullOrEmpty(_SelectedServer) ? _SelectedServer : null;
                
                if (!string.IsNullOrEmpty(_extractInfo.ServerName))
                    
                Application.Current.Dispatcher.BeginInvoke(
                    new Action(() =>
                    {

                     GetDatabases();
                        
                    }),
                    DispatcherPriority.Background,
                    null
                );
                    
                else
                    
                   Databases = new ObservableCollection<string>();
                 }
        }

3 Ответов

Рейтинг:
2

Graeme_Grant

Асинхронный...ждут ТПЛ основы[^ это и есть ответ. Разверните задачу в другом потоке, чтобы освободить поток пользовательского интерфейса и остановить его замораживание.

Многопоточная программа-это то, что требует больших инвестиций в обучение. Лучше всего проверить следующие ресурсы от гуру TPL, прежде чем делать какую-либо работу:

* Async и await введение[^] - Стивен Клири (много или полезной информации в его блоге)

* Асинхронное Программирование Демистифицировано - YouTube[^] Автор: Стивен Клири

* Асинхронные рекомендации для C# и Visual Basic - YouTube[^] по Мадс Торгерсен[^] - Главный архитектор языка в Microsoft. Это использует подход проблемы и решения - очень полезно!


Рейтинг:
0

Member 12699051

Привет,
Я думаю, что вам нужно время, чтобы обновить список баз данных.
Вы можете использовать backgroundworker для обновления этого списка.
Я буду использовать этот сценарий:
- удалить список баз данных после выбора сервера и отключить управление базой данных
- запустите backgroundworker, чтобы получить новый список, который будет отправлен в качестве параметра в завершенном событии
- В завершенной обработке событий установите новый список базы данных и включите управление.

С уважением


D-Kishore

Привет, у вас есть образец заявки? Если у вас есть, пожалуйста, напишите здесь. Спасибо

Рейтинг:
0

Pete O'Hanlon

Если вы используете .NET 4.5 и выше, я бы рекомендовал вам воспользоваться преимуществами новых функций для перемещения ObservableCollection из диспетчера. В принципе, вы хотите начать с чего-то вроде этого:

public class MyViewModel
{
  private readonly object _lock = new object();
  public ObservableCollection<string> Servers { get; private set; }
  public MyViewModel()
  {
    _servers = new ObservableCollection<string>();
    BindingOperations.EnableCollectionSynchronization(Servers, _lock);
  }

  public async void UpdateServers()
  {
    await Task.Run(()=>
      {
        MySlowService slowService = new MySlowService();
        string[] servers = await slowService.GetSlowOperation();
        foreach (string server in servers)
        {
          Servers.Add(server);
        }
      });
  }
}
Обратите внимание, что это всего лишь пример, чтобы показать вам, как сочетать эти методы; вам придется проделать работу, чтобы интегрировать это в ваше решение.


Graeme_Grant

Слышали ли вы пословицу: "Дай человеку рыбу, и ты накормишь его на день; научи человека ловить рыбу, и ты накормишь его на всю жизнь" [^Я пытался дать ему инструменты, чтобы понять, почему. Теперь он пойдет кратчайшим путем... Мы оба знаем, что многопоточность-это не так просто...

Pete O'Hanlon

Не читая ваши ссылки, он не получит ярлык От этого; это далеко не рабочий образец.

Graeme_Grant

Этого достаточно, чтобы сделать его опасным... У Мэдс видео есть ответ, который ему нужен ;)