WPF MVVM C# – Как привязать текст кнопки к выражению LINQ и динамически его изменять? ⇐ C#
-
Anonymous
WPF MVVM C# – Как привязать текст кнопки к выражению LINQ и динамически его изменять?
I would like to bind button text to a LINQ expression, like this:
public string CloseButtonText => Roles.Any(r => r.IsChanged) ? "Save and close" : "Close"; ...but it's not working. The text is properly set at startup, but it doesn't change when any of the RoleViewModel objects change.
This is how I've set it up.
public class RoleSelectionViewModel : ViewModelBase { public RoleSelectionViewModel() { LoadRoles(); } private readonly ObservableCollection _roles = []; public IList Roles => _roles; public string CloseButtonText => Roles.Any(r => r.IsChanged) ? "Save and close" : "Close"; private void LoadRoles() { // Prevents crash when trying to read XML roles during design-time. if (DesignerProperties.GetIsInDesignMode(new System.Windows.DependencyObject())) { return; } var roles = [ .. RolesManagement.ReadRolesXml().OrderBy(r => r.RoleName), ]; roles.ForEach(r => Roles.Add(new RoleViewModel(r))); } // rest of the class... public class RoleViewModel : ViewModelBase { public RoleViewModel() { } public RoleViewModel(Role role) => Role = role; public Role Role { get; protected set; } public int RoleId => Role.RoleId; public string RoleName => Role.RoleName; public string Name { get { return Role.IssuedBy; } set { Role.IssuedBy = value; OnPropertyChanged(); } } public string Department { get { return Role.Department; } set { Role.Department = value; OnPropertyChanged(); } } public string Email { get { return Role.Email; } set { Role.Email = value; OnPropertyChanged(); } } // etc... public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private bool _isChanged = false; public bool IsChanged { get { return _isChanged; } set { _isChanged = value; OnPropertyChanged(); } } protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); if (propertyName != nameof(IsChanged)) { IsChanged = true; } } } I also tried manually subscribing to the RoleViewModel.PropertyChanged event, but it didn't work either. Weirdly enough Role_PropertyChanged triggers when I click the close button, but not when any of the role properties change.
foreach (var role in Roles) { role.PropertyChanged += Role_PropertyChanged; } private void Role_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(RoleViewModel.IsChanged)) { this.OnPropertyChanged(nameof(CloseButtonText)); } } EDIT: I tried subscribing to the CollectionChanged event of the ObservableCollection, but no dice. The Role_PropertyChanged method only triggers when I actually click the Close button; I've no idea why.
public string CloseButtonText { get; set; } = "Close"; private void LoadRoles() { _roles.CollectionChanged += Roles_CollectionChanged; // rest of the method unchanged } private void Roles_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (RoleViewModel item in e.OldItems) { item.PropertyChanged -= Role_PropertyChanged; } } if (e.NewItems != null) { foreach (RoleViewModel item in e.NewItems) { item.PropertyChanged += Role_PropertyChanged; } } } private void Role_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (sender is RoleViewModel role && role.IsChanged && e.PropertyName == nameof(RoleViewModel.IsChanged)) { CloseButtonText = "Save and close"; this.OnPropertyChanged(nameof(CloseButtonText)); } }
Источник: https://stackoverflow.com/questions/781 ... and-have-i
I would like to bind button text to a LINQ expression, like this:
public string CloseButtonText => Roles.Any(r => r.IsChanged) ? "Save and close" : "Close"; ...but it's not working. The text is properly set at startup, but it doesn't change when any of the RoleViewModel objects change.
This is how I've set it up.
public class RoleSelectionViewModel : ViewModelBase { public RoleSelectionViewModel() { LoadRoles(); } private readonly ObservableCollection _roles = []; public IList Roles => _roles; public string CloseButtonText => Roles.Any(r => r.IsChanged) ? "Save and close" : "Close"; private void LoadRoles() { // Prevents crash when trying to read XML roles during design-time. if (DesignerProperties.GetIsInDesignMode(new System.Windows.DependencyObject())) { return; } var roles = [ .. RolesManagement.ReadRolesXml().OrderBy(r => r.RoleName), ]; roles.ForEach(r => Roles.Add(new RoleViewModel(r))); } // rest of the class... public class RoleViewModel : ViewModelBase { public RoleViewModel() { } public RoleViewModel(Role role) => Role = role; public Role Role { get; protected set; } public int RoleId => Role.RoleId; public string RoleName => Role.RoleName; public string Name { get { return Role.IssuedBy; } set { Role.IssuedBy = value; OnPropertyChanged(); } } public string Department { get { return Role.Department; } set { Role.Department = value; OnPropertyChanged(); } } public string Email { get { return Role.Email; } set { Role.Email = value; OnPropertyChanged(); } } // etc... public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private bool _isChanged = false; public bool IsChanged { get { return _isChanged; } set { _isChanged = value; OnPropertyChanged(); } } protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); if (propertyName != nameof(IsChanged)) { IsChanged = true; } } } I also tried manually subscribing to the RoleViewModel.PropertyChanged event, but it didn't work either. Weirdly enough Role_PropertyChanged triggers when I click the close button, but not when any of the role properties change.
foreach (var role in Roles) { role.PropertyChanged += Role_PropertyChanged; } private void Role_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(RoleViewModel.IsChanged)) { this.OnPropertyChanged(nameof(CloseButtonText)); } } EDIT: I tried subscribing to the CollectionChanged event of the ObservableCollection, but no dice. The Role_PropertyChanged method only triggers when I actually click the Close button; I've no idea why.
public string CloseButtonText { get; set; } = "Close"; private void LoadRoles() { _roles.CollectionChanged += Roles_CollectionChanged; // rest of the method unchanged } private void Roles_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (RoleViewModel item in e.OldItems) { item.PropertyChanged -= Role_PropertyChanged; } } if (e.NewItems != null) { foreach (RoleViewModel item in e.NewItems) { item.PropertyChanged += Role_PropertyChanged; } } } private void Role_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (sender is RoleViewModel role && role.IsChanged && e.PropertyName == nameof(RoleViewModel.IsChanged)) { CloseButtonText = "Save and close"; this.OnPropertyChanged(nameof(CloseButtonText)); } }
Источник: https://stackoverflow.com/questions/781 ... and-have-i
Мобильная версия