#c# #xaml #uwp #binding
#c# #xaml #uwp #обязательный
Вопрос:
3 шага вложенное строковое свойство не обновляет пользовательский интерфейс. Когда я обновляю свойство EvidenceName, оно не сразу отражается на пользовательском интерфейсе, пока я не вернусь назад и снова не перейду на эту страницу, и в этом случае viewmodel снова инициализируется.
У меня есть страница xaml со следующим кодом :
<TextBlock Text="{x:Bind ViewModel.SelectedEvidence.EvidenceName, Mode=OneWay}" />
Свойство ViewModel в коде позади :
public EvidenceViewModel ViewModel { get; } = new EvidenceViewModel();
Выбранное свойство доказательства в EvidenceViewModel :
public Evidence SelectedEvidence
{
get => _selectedEvidence;
set => Set(ref _selectedEvidence, value); //this calls for RaisePropertyChanged
}
EvidenceViewModel происходит от наблюдаемого класса для повышения изменений свойств.
public class Observable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
if (Equals(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Свойство EvidenceName в классе Evidence
public string EvidenceName
{
get { return _evidenceName; }
set
{
if (_evidenceName != value)
{
_evidenceName = value;
RaisePropertyChanged();
}
}
}
Обновление 1
если я помещу простое строковое свойство непосредственно в EvidenceViewModel и привяжу текстовый блок пользовательского интерфейса к этому строковому свойству, изменения отразятся в реальном времени, как и ожидалось.
Обновление 2
После некоторой дальнейшей отладки я обнаружил, что любое свойство, которое наследуется классом от родительского класса, плохо работает при привязке, поэтому свойство EvidenceName фактически исходило из родительского класса EvidenceBase и наследовалось в дочерний класс Evidence .
Обновление 3
Код для класса доказательств в сгенерированном Nswagger файле для клиента
Код для класса EvidenceBase
Свойство EvidenceName, которое фактически существует в классе EvidenceBase
RasiePropertyChanged код в базе доказательств
Комментарии:
1. Не могли бы вы предоставить исходный код
RaisePropertyChanged
, пожалуйста? Немного странно, что код содержитSet
,OnPropertyChanged
иRaisePropertyChanged
все ли они взяты из одного и того же инструментария MVVM?2. @MartinZikmund механизм изменения свойств raise происходит из сгенерированного файла nswag, поскольку эти классы моделей на самом деле являются таблицами db в dotnetcore, и nswagger используется для связывания этого с клиентским приложением.
3. @MartinZikmund Пожалуйста, ознакомьтесь с Обновлением 3 моего вопроса, которое может помочь прояснить ваш вопрос о PropertyChanged, и это событие PropertyChanged отлично работает для всех свойств, если они не наследуются от абстрактного класса, как в этом случае.
Ответ №1:
Вы могли бы позволить Evidence
классу наследовать от Observable
класса и вызвать OnPropertyChanged
метод в EvidenceName .
Например:
public class Evidence:Observable
{
private string _evidenceName;
public string EvidenceName
{
get { return _evidenceName; }
set
{
if (_evidenceName != value)
{
_evidenceName = value;
OnPropertyChanged("EvidenceName");
}
}
}
}
Обновление:
Я протестировал код из вашего обновления 3 и обнаружил, что проблема заключается в переопределениях в Evidence
классе.
Пожалуйста, проверьте следующий код:
private void Button_Click(object sender, RoutedEventArgs e)
{
ViewModel.SelectedEvidence.EvidenceName = "testName";
}
public abstract partial class EvidenceBase : System.ComponentModel.INotifyPropertyChanged
{
private string _evidenceName;
[Newtonsoft.Json.JsonProperty("evidenceName",Required =Newtonsoft.Json.Required.Default,NullValueHandling =Newtonsoft.Json.NullValueHandling.Ignore)]
public string EvidenceName
{
get { return _evidenceName; }
set
{
if(_evidenceName!=value)
{
_evidenceName = value;
RaisePropertyChanged("EvidenceName");
}
}
}
protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public partial class Evidence : EvidenceBase, System.ComponentModel.INotifyPropertyChanged
{
//Remove the override of PropertyChanged property and RaisePropertyChanged method to avoid hide the ones inherited from base class.
}
public class Observable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public class EvidenceViewModel:Observable
{
private Evidence _selectedEvidence;
public Evidence SelectedEvidence
{
get { return _selectedEvidence; }
set
{
Set(ref _selectedEvidence, value);
}
}
public EvidenceViewModel()
{
_selectedEvidence = new Evidence();
}
}
Если код не может точно указать ваш код о PropertyChanged, пожалуйста, не стесняйтесь обращаться ко мне.
Комментарии:
1. Не могу этого сделать, потому что механизм изменения свойств raise происходит из сгенерированного файла nswag, поскольку эти классы моделей на самом деле являются таблицами БД в dotnetcore, и nswagger используется для связи этого с клиентским приложением. Пожалуйста, ознакомьтесь с Обновлением 3 моего вопроса, которое может помочь уточнить PropertyChanged , и это событие PropertyChanged отлично работает для всех свойств, если они не наследуются от абстрактного класса, как в этом случае.
2. Я обновил свой ответ, вы можете проверить обновление, чтобы узнать, может ли оно соответствовать вашим требованиям.
3. да, ваше обновленное решение, похоже, работает, я только что прокомментировал событие Propertychanged и поднял значение PropertyChanged в классе «Доказательства». Но проблема в том, что этот файл автоматически генерируется файлом nswag, поэтому я не уверен, как настроить файл nswag или классы моделей, поэтому каждый раз, когда генерируется файл nswag_Generated, он не включает событие PropertyChanged в дочерние классы, и что, если дочерний класс также имеет некоторые собственные свойства, не уверен, как обрабатыватьэто.
4. Но в любом случае ваш ответ затрагивает основную проблему, поэтому я отмечаю его как выполненный 🙂
5. Я думаю, я должен просто создавать интерфейсы и добавлять все дочерние свойства вручную в классы и полностью удалять родительские абстрактные классы?