无法解释的WPF绑定错误。源属性未更新

时间:2015-06-24 22:33:12

标签: c# wpf mvvm telerik

我在MVVM中使用RadListBox在两个RadListBox之间进行拖放。它们中的每一个都包含一个ObservableCollection,其中ApplicationPermission实现了INotifyPropertyChanged。 DataContext是视图模型。

public class PermissionPortfolio : INotifyPropertyChanged, IEquatable<PermissionPortfolio>
{
    private string _systemId;
    private string _shortName;
    private string _accessType;
    private decimal _accountId;
    private string _longName;


    public string LongName
    {
        get { return _longName; }
        set
        {
            _longName = value; 
            OnPropertyChanged();
        }
    }

    public string SystemId
    {
        get { return _systemId; }
        set
        {
            _systemId = value; 
            OnPropertyChanged();
        }
    }

    public string ShortName
    {
        get { return _shortName; }
        set
        {
            _shortName = value; 
            OnPropertyChanged();
        }
    }

    public string AccessType
    {
        get { return _accessType; }
        set
        {
            _accessType = value;
            OnPropertyChanged();
        }
    }

    public decimal AccountId
    {
        get { return _accountId; }
        set
        {
            _accountId = value; 
            OnPropertyChanged();
        }
    }

    public bool Equals(PermissionPortfolio other)
    {
        return other.ShortName.Equals(ShortName) &&
               other.SystemId.Equals(SystemId) && other.AccountId == AccountId;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

我已经制作了一个自定义ListBoxDragDropBehavior,它将把drop放到第二个列表框中:

public class UserPortfolioListBoxDragDropBehavior : ListBoxDragDropBehavior
{
    public override void Drop(DragDropState state)
    {
        if (state.IsSameControl) return;
        foreach (PermissionPortfolio portfolio in state.DraggedItems)
        {
            if (String.IsNullOrEmpty(portfolio.AccessType))
            {
                AccessTypeDialog window = new AccessTypeDialog();
                if (window.ShowDialog() == true)
                {
                    portfolio.AccessType = window.Answer();
                }
            }
            else
            {
                DragDropCanceled(state);
                return;
            }
        }
        base.Drop(state);
    }

}

我的XAML:

<StackPanel Grid.Row="2" Grid.Column="1" Margin="5">
            <Label Content="Available portfolios:"></Label>
            <telerik:RadListBox x:Name="AllPortfolios" TextPath="ShortName" AllowDrop="True" ItemTemplate="{StaticResource AvailablePortfolioCustomTemplate}" ItemContainerStyle="{StaticResource DraggableListBoxItem}" MaxHeight="200" SelectionMode="Extended" ItemsSource="{Binding Path=AllPortfolios, Mode=TwoWay}" MinHeight="20" Margin="10" >
                <telerik:RadListBox.DragDropBehavior>
                    <telerik:ListBoxDragDropBehavior/>
                </telerik:RadListBox.DragDropBehavior>
            </telerik:RadListBox>
        </StackPanel>
        <StackPanel Grid.Row="2" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <StackPanel Grid.Row="2" Grid.Column="2" Margin="5">
            <Label Content="Current portfolios for user:"></Label>
            <telerik:RadListBox x:Name="UserPortfolios" AllowDrop="True" ItemTemplate="{StaticResource UserPortfoliosCustomTemplate}" ItemContainerStyle="{StaticResource DraggableListBoxItem}" SelectionMode="Extended" ItemsSource="{Binding Path=UserPortfolios, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" MinHeight="20" Margin="10" MaxHeight="200">
                <telerik:RadListBox.DragDropBehavior>
                    <!--<telerik:ListBoxDragDropBehavior/>-->
                    <meshPermissionsGui:UserPortfolioListBoxDragDropBehavior/>
                </telerik:RadListBox.DragDropBehavior>
            </telerik:RadListBox>
        </StackPanel>

当在MainWindowViewModel上按下更新按钮时,它会触发执行此操作的WriteAll命令:

// Applications

            List<PermissionApplication> appsToDelete = new List<PermissionApplication>();
            List<PermissionApplication> appsToAddOrEdit = new List<PermissionApplication>();

            foreach (
                PermissionApplication permissionApplication in _vm.Model.GetApplicationsForUser(_vm.SelectedUser))
            {
                if (!_vm.UserApplications.Contains(permissionApplication)) // remove ones that were deleted
                    appsToDelete.Add(permissionApplication);
            }
            foreach (PermissionApplication permissionApplication in _vm.UserApplications) // add or edit new ones
            {
                appsToAddOrEdit.Add(permissionApplication);
            }


            _vm.Model.AddOrEditUserApplications(appsToAddOrEdit, _vm.SelectedUser);
            _vm.Model.DeleteUserApplications(appsToDelete, _vm.SelectedUser);

            // end applications
            // Groups
            List<Group> groupsToDelete = new List<Group>();
            List<Group> groupsToAddOrEdit = new List<Group>();

            foreach (Group g in _vm.Model.GetGroupsForUser(_vm.SelectedUser))
            {
                if (!_vm.UserGroups.Contains(g))
                    groupsToDelete.Add(g);
            }

            foreach (Group g in _vm.UserGroups)
            {
                groupsToAddOrEdit.Add(g);
            }

            _vm.Model.AddOrEditUserGroups(groupsToAddOrEdit, _vm.SelectedUser);
            _vm.Model.DeleteUserGroups(groupsToDelete, _vm.SelectedUser);

            //ends groups
            //Portfolios

            List<PermissionPortfolio> portfoliosToDelete = new List<PermissionPortfolio>();
            List<PermissionPortfolio> portfoliosToAddOrEdit = new List<PermissionPortfolio>();

            foreach (PermissionPortfolio portfolio in _vm.Model.GetUserPortfolios(_vm.SelectedUser))
            {
                if (!_vm.UserPortfolios.Contains(portfolio))
                    portfoliosToDelete.Add(portfolio);
            }

            foreach (PermissionPortfolio portfolio in _vm.UserPortfolios)
            {
                portfoliosToAddOrEdit.Add(portfolio);
            }

            _vm.Model.AddOrEditUserPortfolios(portfoliosToAddOrEdit, _vm.SelectedUser);
            _vm.Model.DeleteUserPortfolios(portfoliosToDelete, _vm.SelectedUser);

            // end portfolios

当用户将一个拖入第二个框时,无论目标框的先前状态如何,都应编写该框中的所有内容。如果先前删除了某些内容,它将从数据库中删除。整个事情应该是一个管理数据库权限的GUI。

可观察集合的count属性始终是正确的。但有时这些项目是不正确的。它可以在前5-6次工作,然后第7次工作。我完全难过了。

感谢您的帮助!

编辑:我在ViewModel中的完整命令类:

public class WriteAllCommand : ICommand
    {
        public MainWindowViewModel Vm
        {
            get { return _vm; }
            set
            {
                _vm = value; 
                Debugger.Break();
            }
        }


        public WriteAllCommand(MainWindowViewModel vm)
        {
            Vm = vm;
        }

        public void Execute(object parameter)
        {
            AppConfiguration.Log.Write(LogLevel.Info, "WriteAll Command Activated");

            // Applications

            List<PermissionApplication> appsToDelete = new List<PermissionApplication>();
            List<PermissionApplication> appsToAddOrEdit = new List<PermissionApplication>();

            foreach (
                PermissionApplication permissionApplication in Vm.Model.GetApplicationsForUser(Vm.SelectedUser))
            {
                if (!Vm.UserApplications.Contains(permissionApplication)) // remove ones that were deleted
                    appsToDelete.Add(permissionApplication);
            }
            foreach (PermissionApplication permissionApplication in Vm.UserApplications) // add or edit new ones
            {
                appsToAddOrEdit.Add(permissionApplication);
            }


            Vm.Model.AddOrEditUserApplications(appsToAddOrEdit, Vm.SelectedUser);
            Vm.Model.DeleteUserApplications(appsToDelete, Vm.SelectedUser);

            // end applications
            // Groups
            List<Group> groupsToDelete = new List<Group>();
            List<Group> groupsToAddOrEdit = new List<Group>();

            foreach (Group g in Vm.Model.GetGroupsForUser(Vm.SelectedUser))
            {
                if (!Vm.UserGroups.Contains(g))
                    groupsToDelete.Add(g);
            }

            foreach (Group g in Vm.UserGroups)
            {
                groupsToAddOrEdit.Add(g);
            }

            Vm.Model.AddOrEditUserGroups(groupsToAddOrEdit, Vm.SelectedUser);
            Vm.Model.DeleteUserGroups(groupsToDelete, Vm.SelectedUser);

            //ends groups
            //Portfolios

            List<PermissionPortfolio> portfoliosToDelete = new List<PermissionPortfolio>();
            List<PermissionPortfolio> portfoliosToAddOrEdit = new List<PermissionPortfolio>();

            foreach (PermissionPortfolio portfolio in Vm.Model.GetUserPortfolios(Vm.SelectedUser))
            {
                if (!Vm.UserPortfolios.Contains(portfolio))
                    portfoliosToDelete.Add(portfolio);
            }

            foreach (PermissionPortfolio portfolio in Vm.UserPortfolios)
            {
                portfoliosToAddOrEdit.Add(portfolio);
            }

            Vm.Model.AddOrEditUserPortfolios(portfoliosToAddOrEdit, Vm.SelectedUser);
            Vm.Model.DeleteUserPortfolios(portfoliosToDelete, Vm.SelectedUser);

            // end portfolios


            Vm.Refresh.Execute(null);

        }

        bool _canexecute = true;
        private MainWindowViewModel _vm;
        public bool CanExecute(object parameter) { return _canexecute; }
        public event EventHandler CanExecuteChanged { add { } remove { } }
    }

调用命令时的Binding调试。这是失败的时候:

System.Windows.Data Warning: 95 : BindingExpression (hash=58169988): Got
PropertyChanged event from MainWindowViewModel (hash=12012133)
System.Windows.Data Warning: 101 : BindingExpression (hash=58169988):   
GetValue at level 0 from MainWindowViewModel (hash=12012133) using RuntimePropertyInfo(UserPortfolios): <null>
System.Windows.Data Warning: 80 : BindingExpression (hash=58169988): TransferValue - got raw value <null>
System.Windows.Data Warning: 89 : BindingExpression (hash=58169988): TransferValue - using final value <null>
System.Windows.Data Warning: 95 : BindingExpression (hash=58169988): Got PropertyChanged event from MainWindowViewModel (hash=12012133)
System.Windows.Data Warning: 101 : BindingExpression (hash=58169988): GetValue at level 0 from MainWindowViewModel (hash=12012133) using RuntimePropertyInfo(UserPortfolios): ObservableCollection`1 (hash=33513495 Count=0)
System.Windows.Data Warning: 80 : BindingExpression (hash=58169988): TransferValue - got raw value ObservableCollection`1 (hash=33513495 Count=0)
System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='System.Collections.ObjectModel.ObservableCollection`1[MeshPermissionsGUI.PermissionPortfolio]' BindingExpression:Path=UserPortfolios; DataItem='MainWindowViewModel' (HashCode=12012133); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Warning: 87 : BindingExpression (hash=58169988): TransferValue - value ObservableCollection`1 (hash=33513495 Count=0) is not valid for target
System.Windows.Data Warning: 88 : BindingExpression (hash=58169988): TransferValue - using fallback/default value ''
System.Windows.Data Warning: 89 : BindingExpression (hash=58169988):     TransferValue - using final value ''

忽略其中的错误。我只是将它绑定到GUI中的文本框以获取此数据。让我感到困扰的是它实际上得到了错误的物品数量。

0 个答案:

没有答案