2017-01-17 9 views
0

Я ищу решение для отключения кнопки входа, пока я получаю ответ из базы данных. Для многопоточности я использую Task. С первым Task я делаю вызов для подключения, затем создаю второй Task для подключения их, чтобы не сделать cross-exception. Насколько я понял, в первом Task я не могу заблокировать кнопку, потому что получаю исключение, которое не могу использовать ресурсы из другого потока.Многопоточность с использованием кнопок Taks/disable и enable в WPF

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

public void LoginIntoApplication(Button loginButton) 
     { 
      dbConn = new DataBaseConnection(loginWindow.loginBox.Text, loginWindow.passwordBox.Password); 
      Task t = new Task(() => 
      { 
       // Get data from db 
       dbConn.Connect(); 
      }); 
      Task t2 = t.ContinueWith(previouseTask => 
      { 
       // Do smth with data 
       loginButton.IsEnabled = false; 
       var status = dbConn.OraCon; 
       if (status.State == ConnectionState.Open) 
       { 
        loginWindow.Hide(); 
        testWindow = new TestWindow(); 
        testWindow.Show(); 
       } 
       else 
       { 
        loginButton.IsEnabled = true; 
       } 


      }, TaskScheduler.FromCurrentSynchronizationContext()); 

      t.Start(); 
     } 

Заранее благодарен!

+0

Оберните свой набор настроек loginButton.IsEnabled в Dispatcher.BeginInvoke или Invoke call - исходя из поведения, которое вам нужно. – VitaliyK

+0

Почему вы используете холодные задачи и 'ContinueWith' вместо' async/await'? Это просто делает ваш код намного сложнее, * и * вы получаете фальшивый асинхронный вызов. PS, кроме соединения, ваш код имеет * no * вызовы базы данных. Где они? –

+0

Что это должно выглядеть с 'async/await'? – yerpy

ответ

3

Самый простой способ выполнить асинхронные операции - использовать асинхронные методы async/await и ADO.NET. Асинхронные методы выполняются в фоновом режиме с использованием портов завершения ввода-вывода, так что им даже не требуется фоновый поток. await ключевого слова гарантирует, что, когда они закончат, выполнение возвращается в поток пользовательского интерфейса:

public async Task LoginIntoApplication(Button loginButton) 
{ 
    try 
    { 
     using (var conn=new OracleConnection(myConnectionString)) 
     { 
      //OpenAsync runs on the background while the UI thread is released 
      await conn.OpenAsync(); 
      //No exception means connection open 
      //At this point we are back on the UI thread. 
      loginButton.IsEnabled = false; 
      loginWindow.Hide(); 
      testWindow = new TestWindow(); 
      testWindow.Show(); 

      var someCommand=new OracleCommand(myQuery,conn); 
      //Run a query asynchronously 
      using(var reader=await someCommand.ExecuteReaderAsync()) 
      { 
       //Work with the reader's results 
      } 
    } 
    catch(Exception exc) 
    { 
     //Oracle refused the connection 
     loginButton.IsEnabled = true; 
    } 
} 

Если открыть или OpenAsync успешно вы знаете связь работала. Если это не так, это вызовет исключение.

Обратите внимание, что вы должны не использовать любое глобальное соединение. Сохранение соединения в течение длительного времени накапливает блокировки и делает обработку исключений намного сложнее. ADO.NET использует пул соединений, чтобы вы могли закрыть соединение, как только вы его закончите, без оплачивая стоимость фактического создания нового подключения. Это одна из самых важных функций масштабируемости для любого приложения базы данных.

+0

Единственное, что я хотел бы изменить, это использовать команду вместо события, представление не должно регистрироваться в – MikeT

+0

@MikeT, это не событие. Вот почему у него есть подпись async Task. Это всего лишь метод. Говоря об улучшениях, было бы лучше использовать модель MVVM и обновить свойства ViewModel вместо изменения пользовательского интерфейса напрямую. –

+0

Я предположил, что вызов был согласован с событием нажатия кнопок, если его нет, то он не должен обрабатывать элементы управления представлением напрямую, поэтому ICommand определяет событие CanExecuteChanged – MikeT