为什么collection1具有与collection2相同的值?

时间:2018-06-29 11:12:45

标签: c# wpf mvvm

我想要的

所以我想检查2 ObservableCollections是否相等。 如果是这样,则返回Nothing Changed(collection1和collection2相同)。 否则返回Something Changed

问题

现在的问题是,即使我更改集合2中的项目,两个集合也包含相同的值。

我发布了一些代码和调试结果的gif,向您展示了我得到的结果。 我不明白,为什么单击“保存”按钮后两个收藏夹都相同。

代码

ViewModel

在我的ViewModel中,我有: 1 ObservableCollection被称为RightsCollection。 这应该包含我的XAML上的权利,可以通过ToggleButton进行更改。

1个Employee类,其中ObservableCollection<Groups>所在,在Groups.Col内有一个ObservableCollection<Rights>,其中包含从DataBase加载的默认组权限,不能改变了。

注意:我的get set始终是相同的。它们只是具有其他名称,并且DataTypes考虑其字段数据类型。

private Employee _singleEmployee = new Employee();
public Employee SingleEmployee
{
    get => _singleEmployee;
    set
    {
        if (_singleEmployee == value) return;
        _singleEmployee = value;
        OnPropertyChanged("SingleEmployee");
    }
}

private ObservableCollection<Groups> _groupsCollection = new ObservableCollection<Groups>();
// public get set GroupsCollection (same like first).

private ObservableCollection<Rights> _rightsCollection = new ObservableCollection<Rights>();
// public get set RightsCollection (same like first).

员工类别

public class Employee : INotifyPropertyChanged
{
    private int _employeeId;
    private string _firstName;
    private Groups _group = new Group();

    // public get set EmployeeId (Same like first).
    // public get set Group (same like first).
}

权利舱

private int _rightId;
private string _rightName;
private bool _hasRight;

// Again get set is same

网上论坛

private int _groupId;
private string _groupName;
private ObservableCollection<Rights> _rights;

// Again, same Get/Set like always

XAML

在我的XAML中,我有: ComboBoxComboBox.ItemsSource绑定到GroupsCollectionComboBox.SelectedValue绑定到SingleEmployee.Group

因此,在更改组合框时,将设置“单个雇员的组”。

ComboBox也有一个SelectionChanged事件,我将RightsCollection设置为SingleEmployee.Group.Rights。这样,两者现在都包含相同的项目/值。

它还包含一个ItemsControl,我可以在其中自行设置权限(以及在ComboBox.SelectionChanged起作用时将加载权限的位置)。

<ComboBox x:Name="GroupComboBox" ItemsSource="{Binding GroupsCollection}" SelectedValue="{Binding SingleEmployee.Group}" DisplayMemberPath="GroupName" SelectionChanged="GroupComboBox_SelectionChanged">

ItemsControl

<ItemsControl ItemsSource="{Binding RightsCollection}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <DockPanel>
                    <ToggleButton DockPanel.Dock="Right" Margin="10" IsChecked="{Binding HasRight}"/>
                    <TextBlock FontSize="15" FontWeight="Bold" Text="{Binding RightName}" DockPanel.Dock="Left" Margin="10" />
                </DockPanel>
                <TextBlock Text="{Binding RightsDesc}" Margin="30 0 0 10" TextWrapping="Wrap"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

代码隐藏中的SelectionChanged事件

Debug.WriteLine("############ SelectionChanged Event ############");
Debug.WriteLine("# Before Change ##");
Debug.WriteLine($"SingleEmployee.Group.Rights.Count: {_viewModel.SingleEmployee.Group.Rights.Count} | RightsCollection.Count: {_viewModel.RightsCollection.Count}");
for (int i = 0; i < _viewModel.SingleEmployee.Group.Rights.Count; i++)
{
    Debug.WriteLine($"Name: {_viewModel.SingleEmployee.Group.Rights[i].RightName}, HasRight: {_viewModel.SingleEmployee.Group.Rights[i].HasRight} || Name: {_viewModel.RightsCollection[i].RightName}, HasRight: {_viewModel.RightsCollection[i].HasRight}");
}

_viewModel.RightsCollection = _viewModel.SingleEmployee.Group.Rights;

Debug.WriteLine("# After Change #");
Debug.WriteLine($"SingleEmployee.Group.Rights.Count: {_viewModel.SingleEmployee.Group.Rights.Count} | RightsCollection.Count: {_viewModel.RightsCollection.Count}");
for (int i = 0; i < _viewModel.SingleEmployee.Group.Rights.Count; i++)
{
    Debug.WriteLine$"Name: {_viewModel.SingleEmployee.Group.Rights[i].RightName}, HasRight: {_viewModel.SingleEmployee.Group.Rights[i].HasRight} || Name: {_viewModel.RightsCollection[i].RightName}, HasRight: {_viewModel.RightsCollection[i].HasRight}");
}

Debug.WriteLine("########## SelectionChanged Event END ##########");
Debug.WriteLine("################################################");

在代码隐藏中设置ViewModel

private readonly EmployeeViewModel _viewModel;

// constructor...
{
_viewModel = (EmployeeViewModel) DataContext;
}

保存按钮命令方法

Debug.WriteLine("############## After Button Click ##############");
for (int i = 0; i < RightsCollection.Count; i++)
{
    Debug.WriteLine($"Name: {SingleEmployee.Group.Rights[i].RightName}, HasRight: {SingleEmployee.Group.Rights[i].HasRight} || Name: {RightsCollection[i].RightName}, HasRight: {RightsCollection[i].HasRight}");
}
Debug.WriteLine("################################################");

bool equal = RightsCollection.Count == SingleEmployee.Group.Rights.Count && RightsCollection.All(x => SSingleEmployee.Group.Rights.Contains(x));

Debug.WriteLine(equal ? "Nothing Changed" : "Something changed");

我尝试过的

SelectionChanged事件

// No Success
var collection = new ObservableCollection<Rights>(_viewModel.SingleEmployee.Group.Rights);
_viewModel.RightsCollection = collection;

// No Success
foreach(var item in _viewModel.SingleEmployee.Group.Rights)
    _viewModel.RightsCollection.Add(item);

调试结果

SelectionChangedResult SelectionChangedResult (GIF) |

SelectionChangedResult SelectionChangedResult (Picture)

单击按钮后 After Button Click (GIF)

单击按钮后 After Button Click (Picture)

2 个答案:

答案 0 :(得分:2)

_viewModel.RightsCollection = _viewModel.SingleEmployee.Group.Rights;

左集合与右集合具有相同的引用。 因此,如果更改一个集合,它将反映在另一个集合中。

ObservableCollection<Whatever> _viewModel.RightsCollection = new ObservableCollection<Whatever>();

foreach(var item in _viewModel.SingleEmployee.Group.Rights)
    _viewModel.RightsCollection.Add(item);

答案 1 :(得分:0)

我在SelectionChanged Event中删除了以下行,解决了此问题:

_viewModel.RightsCollection = _viewModel.SingleEmployee.Group.Rights;

并替换为:

for (int i = 0; i < _viewModel.SingleEmployee.Group.Rights.Count; i++)
{
    if (_viewModel.SingleEmployee.Group.Rights[i].HasRight != _viewModel.RightsCollection[i].HasRight)
    {
        _viewModel.RightsCollection[i].HasRight = _viewModel.SingleEmployee.Group.Rights[i].HasRight;
    }
}

因为两个集合几乎相同,所以它们将始终具有相同数量的项目,因此我可以使用for循环。 如果值不相同,则该值将更改。

这样,我不创建反射(我想),所以它起作用了。

现在唯一的是

bool equal = RightsCollection.Count == SingleEmployee.Group.Rights.Count && RightsCollection.All(x => SingleEmployee.Group.Rights.Contains(x)); 

不起作用,但我也会在此处使用for循环,该循环检查项目是否包含相同的值,如果不相同,则"Something changed"