Изменения пользовательского интерфейса MVVM OnpropertyChange отложены - PullRequest
0 голосов
/ 01 ноября 2018

У меня есть поле со списком, который, пока он заполнен, я хочу, чтобы он был заменен в пользовательском интерфейсе сообщением о загрузке. я сделал это с помощью текстового поля, показывающего сообщение и связывающего видимость обоих объектов в модели представления (IsShowAuthComboBox & LoadingAuthenticationMsg)

вот код XAML

<ComboBox x:Name="ComboBoxAuthSource"
    Grid.Row="3"
    Style="{StaticResource ComboBoxStyle}"
    SelectedItem ="{Binding SelectedAuthenticationSource,UpdateSourceTrigger=PropertyChanged}"
    ItemsSource="{Binding AuthenticationSource,UpdateSourceTrigger=PropertyChanged}"  
    Visibility= "{Binding IsShowAuthComboBox, Converter={StaticResource BoolToVis}}" />

<TextBox x:Name="ComboBoxAuthCover"
    Grid.Row="3" Grid.Column="{StaticResource TableColumn}"
    Style="{StaticResource  FieldBoxStyle }"
    FontSize="12"
    IsReadOnly="True"
    Visibility="{Binding IsShowGettingAuthenticationMsg, Converter={StaticResource BoolToVis}}"
    Text="{Binding LoadingAuthenticationMsg,UpdateSourceTrigger=PropertyChanged,Mode=OneWay,FallbackValue='Loading authentication sources...'}" />

А вот модель представления

public bool IsShowAuthComboBox
    {
        set
        {
            if (_isShowAuthenticationComboBox != value)
            {                   
                _isShowAuthenticationComboBox = value;
                OnPropertyChanged("IsShowAuthComboBox");
                OnPropertyChanged("IsShowGettingAuthenticationMsg");
            }              
        }
        get =>_isShowAuthenticationComboBox; 
    }

public bool IsShowGettingAuthenticationMsg => !_isShowAuthenticationComboBox;


 public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            Log.Write(LogClass.General, LogLevel.Debug,
                $"{propertyName} update triggerd",
                _moduleName);
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

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

что мне здесь не хватает?

РЕДАКТИРОВАТЬ: это также происходит при проверке IP, более простой код. вот код

 public string SelectedServer
        {
            get => _selectedServer;
            set
            {
                lock (_lockObj)
                {               
                    IsShowAuthComboBox = false;
                    if (!IsValideIp(value))

                    //some code
                    IsShowAuthComboBox  = true;
                }
            }

bool IsValideIp(string ip)
{
   //some code

  //calls the server sync
   return RemotingConfigurator.GetServerConfig(ip).isValid;
}

Ответы [ 2 ]

0 голосов
/ 04 ноября 2018

это то, что я в итоге делал. переместил изменения пользовательского интерфейса со слоя данных в viewModel (SetUiOnWait)

public string SelectedServer
        {
            get => _selectedServer;


    set
        {
            //IsShowAuthComboBox = false;
            SetUiOnWait(true);

            Log.Write(LogClass.General, LogLevel.Debug,
                $"Server changed from {_selectedServer} to {value} by user",
                _moduleName);

            _selectedServer = value;
            OnPropertyChanged();
            // OnPropertyChanged();

            //workaround for when changing servers when a unique  
            //authentication source is selected causes the selected source to be null :\
            if (AuthenticationSource.Any())
            {
                SelectedAuthenticationSource = AuthenticationSource[0];
            }

            Task.Factory.StartNew(() =>
            {
                LoginInfo.SelectedServer = _selectedServer;

            }).ContinueWith((t) =>
            {
                if(t.Exception !=null)
                {
                    ExceptionLog.Write(t.Exception.GetBaseException(),_moduleName);
                }
                RefreshAuthenticationProperties();
                OnPropertyChanged("IsLimitedClinicalUse");
                OnPropertyChanged("IsNotForClinicalUse");
                SetUiOnWait(false);
            });
        }

 public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    dispatcher.Invoke((Action)(() =>
               {
                   //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));                          
               }));
}

Task.Factory.StartNew () вынуждает и логику выполнять в новом потоке, а изменения пользовательского интерфейса ожидают его завершения.

и вызов в OnPropertyChange заставляет событие обрабатываться потоком пользовательского интерфейса.

0 голосов
/ 01 ноября 2018

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

Что вам нужно сделать, это вызвать IsValideIp в фоновом потоке. Я бы не стал делать это в установщике свойства, а в команде. Вы можете прочитать @ пост Стивена Клири в блоге на эту тему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...