首页 > 解决方案 > 为 BindingGroup 设置 IsDirty

问题描述

BindingGroup用于跟踪 ViewModel 中数据的更改,以便保存或回滚。我的视图看起来像这样:

<UserControl x:Class="UserManagement.Client.Views.UserDetail"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:prism="http://prismlibrary.com/"
             xmlns:viewModels="clr-namespace:UserManagement.Client.ViewModels"
             prism:ViewModelLocator.AutoWireViewModel="True"
             mc:Ignorable="d"
             d:DataContext="{d:DesignInstance viewModels:IUserDetailViewModel}"
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
        <StackPanel.BindingGroup>
            <BindingGroup x:Name="BindingGroup">
                <BindingGroup.ValidationRules>
                    <client:UserDetailValidation ValidationStep="ConvertedProposedValue"/>
                </BindingGroup.ValidationRules>
            </BindingGroup>
        </StackPanel.BindingGroup>
        <TextBlock Text="Display Name:"/>
        <TextBox Text="{Binding User.DisplayName}"/>
        <ListView ItemsSource="{Binding UserGroups}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Display Name" DisplayMemberBinding="{Binding DisplayName}"/>
                </GridView>
            </ListView.View>
        </ListView>
        <Button Content="Edit Groups" Command="{Binding EditGroupsCommand}"/>
        <Button Content="Save" Command="{Binding SaveCommand}" CommandParameter="{Binding ElementName=BindingGroup}"/>
        <Button Content="Cancel" Command="{Binding CancelCommand}" CommandParameter="{Binding ElementName=BindingGroup}"/>
    </StackPanel>
</UserControl>

我的 ViewModel 看起来像这样:

public class UserDetailViewModel : BindableBase, IUserDetailViewModel
{
    private const string DialogParameterNameAssignedGroups = "AssignedGroups";
    private const string DialogTitle = "GroupSelection";
    private readonly IDialogService _dialogService;
    private readonly IUserClientService _userClientService;
    private User _user;

    public UserDetailViewModel(IDialogService dialogService, IUserClientService userClientService)
    {
        _dialogService = dialogService;
        _userClientService = userClientService;
        SaveCommand = new DelegateCommand<BindingGroup>(Save, CanSave);
        CancelCommand = new DelegateCommand<BindingGroup>(Cancel, CanCancel);
        EditGroupsCommand = new DelegateCommand(EditGroups, CanEditGroups);
    }

    public User User
    {
        get => _user;
        set
        {
            SetProperty(ref _user, value);
            RaisePropertyChanged(nameof(User));
            RaisePropertyChanged(nameof(UserGroups));
        }
    }

    public ICollection<Group> UserGroups => new ObservableCollection<Group>(User.Groups);

    public DelegateCommand<BindingGroup> SaveCommand { get; }

    public DelegateCommand EditGroupsCommand { get; }
    
    public DelegateCommand<BindingGroup> CancelCommand { get; }

    private static bool CanSave(BindingGroup bindingGroup)
    {
        return bindingGroup.IsDirty;
    }

    private void Save(BindingGroup bindingGroup)
    {
        if (!bindingGroup.CommitEdit()) return;
        bindingGroup.BeginEdit();
        _userClientService.UpdateUser(User);
    }

    private static bool CanCancel(BindingGroup bindingGroup)
    {
        return bindingGroup.IsDirty;
    }

    private static void Cancel(BindingGroup bindingGroup)
    {
        bindingGroup.CancelEdit();
        bindingGroup.BeginEdit();
    }

    private bool CanEditGroups()
    {
        return _user != null;
    }

    private void EditGroups()
    {
        _dialogService.ShowDialog(DialogTitle, new DialogParameters
        {
            {DialogParameterNameAssignedGroups, new ObservableCollection<Group>(_user.Groups)}
        }, HandleDialogResult);
    }

    private void HandleDialogResult(IDialogResult dialogResult)
    {
        if (dialogResult.Result != ButtonResult.OK) return;
        var assignedGroups = dialogResult.Parameters.GetValue<ICollection<Group>>(
            DialogParameterNameAssignedGroups);
        _user.Groups.Clear();
        foreach (var assignedGroup in assignedGroups)
        {
            _user.Groups.Add(assignedGroup);
        }
        RaisePropertyChanged(nameof(UserGroups));
    }
}

验证类什么都不做:

public class UserDetailValidation : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        return ValidationResult.ValidResult;
    }
}

如果我更改UserName. 我可以保存更改或取消(任何一个选项都会禁用按钮)。但是,如果我更改UserGroups集合(使用单独的对话框),按钮将不会启用,但 UI 会更新。当我更改属性时,我必须更改哪些BindingGroup集合?IsDirtyUserGroups

标签: c#wpfxaml

解决方案


我可能会错过一些东西,但你为什么不在 HandleDialogResult 中设置 IsDirty=true 呢?否则 ObservableCollection 会提供一个事件 CollectionChanged ,您可以注册该事件并在该集合发生更改时收到通知,因此您可以在那里更改 isDirty 。


推荐阅读