0

我的 Senario:我有两个 ListBoxes 绑定到两个不同的 ObervableCollections——形状的集合和颜色的集合,用户可以从中选择以查找具有匹配属性标准的部件号。(我的应用程序中存在更多属性集合,但为了清楚起见,我省略了它们。)

在从两个包含属性值的列表框中进行选择后,我将生成的部件号收集到一个名为ResultingPNsIntersect. (结果部件号的集合显示在第三个列表框中。)

应该发生什么:在两个列表框中的任何一个中进行选择后,拥有 Selected'Attribute' 的结果部件号的交集应该更新,以便只保留相关的部件号。如果选择了一个形状,则包含 的列表框ColorsCollection必须更新,以便只有ColorsCollection与具有 的 PartNumber 相关的颜色属性(在 中)SelectedShape显示在第二个列表框中。

我的问题:选择一个形状后,ResultingPNsIntersect ObservableCollection更新,但 PropertyChanged 通知ColorsCollection永远不会被触发,所以第二个列表框永远不会更新为用户提供更新的颜色属性以供选择。

我以前在其他应用程序中做过这个,没有任何问题。我认为没有必要订阅,CollectionChanged因为我没有在 ResultingPNsIntersect 中编辑属性值——我正在用新值替换集合。请帮我看看我的代码在哪里失败以及为什么失败,以便我能更好地了解 INPC 触发所需的条件。

xaml 绑定:

<ListBox x:Name="SelectFromAvailableShapesLB" DockPanel.Dock="Top"  
         ItemsSource="{Binding AvailableShapesCollection}" 
         DisplayMemberPath="AttVal" 
         SelectedItem="{Binding SelectedShape, Mode=TwoWay}"/>


<ListBox x:Name="SelectFromAvailableColorsLB" DockPanel.Dock="Top"  
         ItemsSource="{Binding AvailableColorsCollection}" 
         DisplayMemberPath="AttVal" 
         SelectedItem="{Binding SelectedColor, Mode=TwoWay}"/>


<ListBox x:Name="PnsResultingFromAttributeSelectionsLB" DockPanel.Dock="Top"  
         ItemsSource="{Binding ResultingPNsIntersect}" 
         DisplayMemberPath="PartNum" 
         SelectedItem="{Binding SelectedPartNum, Mode=TwoWay}"/>

我的视图模型:

    public ObservableCollection<AttributeValuesLibrary> AvailableShapesCollection
    {
        get
        {
            if (_resultingPNsIntersect != null)
            {
                foreach (PartNumber shape in _resultingPNsIntersect.Where(x => x.ShapeID != null))
                {
                    if (!_availableShapesCollection.Contains(shape.AttributeValuesLibrary_Shape))
                    {
                        this._availableShapesCollection.Add(shape.AttributeValuesLibrary_Shape);
                    }
                }

            }
            return _availableShapesCollection;
        }
        set
        {
            if (_availableShapesCollection != value)
            {
                this._availableShapesCollection = value;
                RaisePropertyChanged("AvailableShapesCollection");
            }
        }
    }


    public ObservableCollection<AttributeValuesLibrary> AvailableColorsCollection
    {
        get
        {
            if (_resultingPNsIntersect != null)
            {
                foreach (PartNumber color in _resultingPNsIntersect.Where(x => x.ColorID != null))
                {
                    if (!_availableColorsCollection.Contains(color.AttributeValuesLibrary_Color))
                    {
                        _availableColorsCollection.Add(color.AttributeValuesLibrary_Color);
                    }
                }

            }
            return _availableColorsCollection;
        }
        set
        {
            if (_availableColorsCollection != value)
            {
                _availableColorsCollection = value;
                RaisePropertyChanged("AvailableColorsCollection");
            }
        }
    }

    public AttributeValuesLibrary SelectedShape
    {
        get
        {
            return _selectedShape;
        }
        set
        {
            if (_selectedShape != value)
            {
                _selectedShape = value;
                RaisePropertyChanged("SelectedShape");
                RaisePropertyChanged("ResultingPNsIntersect");
            }

        }
    }


    public ObservableCollection<ConnectorPartNumber> ConnAttPNResults
    {
        get
        {
            // If a shape has been selected, we need to navigate to it's related PartNumbers and add those to the intersection
            // contained by ResultingPNsIntersection. 
            if (_selectedShape != null)
            {
                var shapeResults = _context.PartNumbers.Where(x => x.AttributeValuesLibrary_Shape.AttValID == _selectedShape.AttValID);

                if (_resultingPNsIntersect != null)
                {
                    var resultsFromPreviousSelection = _resultingPNsIntersect;
                    _resultingPNsIntersect = new ObservableCollection<PartNumber>(resultsFromPreviousSelection.Intersect(shapeResults));
                }
                else if (_resultingPNsIntersect == null)
                {
                    _resultingPNsIntersect = new ObservableCollection<PartNumber>(shapeResults);
                }
              }
            return _resultingPNsIntersect;
        }
        set
        {
            if (_resultingPNsIntersect != value)
            {
                this._resultingPNsIntersect = value;
                RaisePropertyChanged("ResultingPNsIntersect");
                RaisePropertyChanged("AvailableColorsCollection");  <--Not firing!!!!!

            }


        }
    }

提前致谢!

RaisePropertyChanged("AvailableColorsCollection"):: UPDATE :: 如果我将SelectedShape. 但是,当然,它在那里意义不大,因为 AvailableColorsCollection 依赖于ResultingPNsIntersectCollection,它根据属性列表框中的选择而改变。

4

1 回答 1

1

我认为总的来说,您的方法会给您带来问题。与其在属性的 getter 中实现逻辑,不如考虑让属性变得更加“笨拙”。我会将这个逻辑从属性中移出到一个修改你可用选项的辅助方法中:

private readonly ObservableCollection<AttributeValuesLibrary> _availableShapesCollection =
    new ObservableCollection<AttributeValuesLibrary>();
private readonly ObservableCollection<AttributeValuesLibrary> _availableColorsCollection =
    new ObservableCollection<AttributeValuesLibrary>();

public ObservableCollection<AttributeValuesLibrary> AvailableShapesCollection
{
    get { return _availableShapesCollection; }
}

public ObservableCollection<AttributeValuesLibrary> AvailableColorsCollection
{
    get { return _availableColorsCollection; }
}

public AttributeValuesLibrary SelectedShape
{
    get { return _selectedShape; }
    set
    {
        if (_selectedShape != value)
        {
            _selectedShape = value;
            RaisePropertyChanged("SelectedShape");
            SelectedShapeChanged();
        }
    }
}

public ObservableCollection<ConnectorPartNumber> ConnAttPNResults
{
    get { return _resultingPNsIntersect; }
    set
    {
        if (_resultingPNsIntersect != value)
        {
            this._resultingPNsIntersect = value;
            RaisePropertyChanged("ResultingPNsIntersect");
            UpdateAvailableOptions();
        }
    }
}

private void SelectedShapeChanged()
{
    // If a shape has been selected, we need to navigate to it's related 
    // PartNumbers and add those to the intersection contained by ResultingPNsIntersection. 
    if (_selectedShape != null)
    {
        var shapeResults = _context.PartNumbers.Where(x => x.AttributeValuesLibrary_Shape.AttValID == _selectedShape.AttValID);

        if (_resultingPNsIntersect != null)
        {
            var resultsFromPreviousSelection = _resultingPNsIntersect;
            ConnAttPNResults = new ObservableCollection<PartNumber>(resultsFromPreviousSelection.Intersect(shapeResults));
        }
        else
        {
            ConnAttPNResults = new ObservableCollection<PartNumber>(shapeResults);
        }
    }
}

private void UpdateAvailableOptions()
{
    if (_resultingPNsIntersect != null)
    {
        _availableColorsCollection.Clear();
        _availableShapesCollection.Clear();

        foreach (PartNumber color in _resultingPNsIntersect.Where(x => x.ColorID != null).Distinct())
        {
            _availableShapesCollection.Add(color.AttributeValuesLibrary_Color);
        }

        foreach (PartNumber shape in _resultingPNsIntersect.Where(x => x.ShapeID != null).Distinct())
        {
            shapes.Add(shape.AttributeValuesLibrary_Shape);
        }
    }
}

如果您希望拥有可设置的属性,则UpdateAvailableOptions可以创建新集合并将AvailableColorsCollection&AvailableShapesCollection属性设置为新实例(但不需要ObservableCollections)。

实际上,我什至会更进一步。由于您不希望任何人更改您的可用集合,我会让它们返回ReadonlyObersvableCollection实例,并使其返回类型IEnumerable<T>

于 2013-08-09T20:09:12.707 回答