WPF MVVM C# - 如何将按钮的文本绑定到 LINQ 表达式并使其动态更改?

问题描述 投票:0回答:1

我想将按钮文本绑定到 LINQ 表达式,如下所示:

public string CloseButtonText => Roles.Any(r => r.IsChanged) ? "Save and close" : "Close";

...但它不起作用。文本在启动时已正确设置,但当任何 RoleViewModel 对象更改时它不会更改。

我就是这样设置的。

public class RoleSelectionViewModel : ViewModelBase
{
    public RoleSelectionViewModel()
    {
        LoadRoles();
    }
    
    private readonly ObservableCollection<RoleViewModel> _roles = [];
    public IList<RoleViewModel> 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;
        }
    }
}
<Button
    x:Name="Close_Button"
    Width="96"
    Height="30"
    Padding="10,0,10,0"
    Background="#FF838383"
    Foreground="White"
    Command="{Binding CloseCommand}"
    >
    <TextBlock
        x:Name="Close_Button_Text"
        Text="{Binding CloseButtonText}"
        />
</Button>

我也尝试过手动订阅

RoleViewModel.PropertyChanged
事件,但也没有成功。奇怪的是,当我单击关闭按钮时,
Role_PropertyChanged
会触发,但任何角色属性更改时不会触发。

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));
    }
}

编辑:我尝试订阅

CollectionChanged
ObservableCollection
事件,但没有骰子。
Role_PropertyChanged
方法仅在我实际单击“关闭”按钮时触发;我不知道为什么。

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));
    }
}

编辑 2:事实证明,您无法像我最初预期的那样绑定到 LINQ 表达式。然而,在每个

UpdateSourceTrigger=PropertyChanged
的绑定上添加
TextBox
后,它就起作用了。默认似乎是在
TextBox
失去焦点后引发事件。所以完整的绑定应该是这样的:
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
。我仍然必须订阅
CollectionChanged
上的
ObservableCollection
事件,并且还订阅每个
RoleViewModel
PropertyChanged
事件,如第一次编辑中所述。

c# wpf linq mvvm binding
1个回答
0
投票

事实证明,您无法像我最初的意图那样绑定到 LINQ 表达式。我将属性更改为:

public string CloseButtonText { get; set; } = "Close"

我遇到的问题是,该事件没有在我预期的时候(当文本框内容更改时)引发。 然而,在每个

UpdateSourceTrigger=PropertyChanged
的绑定上添加
TextBox
后,它就起作用了。默认似乎是在
TextBox
失去焦点后引发事件。所以完整的绑定应该是这样的:
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
。我仍然必须订阅
CollectionChanged
上的
ObservableCollection
事件,并且还订阅每个
RoleViewModel
PropertyChanged
事件,如第一次编辑中所述。

© www.soinside.com 2019 - 2024. All rights reserved.