我在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中的文本框以获取此数据。让我感到困扰的是它实际上得到了错误的物品数量。