使用 C#/XAML,如何根据第一个组合框的选定项目更新第二个组合框的 ItemsSourceList?

Using C#/XAML, how do I update the ItemsSourceList of a second combobox based on the selected item of the first combobox?

我已经根据 Whosebug 和其他地方的许多示例尝试了多种方法,但就是无法使它起作用。我希望 ComboBox B 的选择列表根据 ComboBox A 中的所选项目而有所不同。有人可以帮我确定我做错了什么吗? (我正在使用 MVVMLight。)

这是两个组合框的 ItemsSources:

private ObservableCollection<SetupSF> _sourceForSFList = new ObservableCollection<SetupSF>();

public ObservableCollection<SetupSF> SourceForSFList
{
    get { return _sourceForSFList; }
    set
    {
        _sourceForSFList = value;
    }
}

private ObservableCollection<SetupSFE> _sourceForSFEList = new ObservableCollection<SetupSFE>();
public ObservableCollection<SetupSFE> SourceForSFEList
{
    get { return _sourceForSFEList; }
    set
    {
        _sourceForSFEList = value;
    }
}

这是选择器。我尝试使用 RelayPropertyChanged,尽管它是一个可观察的集合,但没有效果。我已经通过设置断点验证列表的内容正在更新。列表更新,但显然不会通知第二个组合框。 _selectedSF.OwnedSFEs 本身就是一个 ObservalbleCollection。

public SetupSubfactor SelectedSF
{
    get { return _selectedSF; }
    set 
    {
        _selectedSF = value;
        if (_selectedSF != null)
        {
            SourceForSFEList = _selectedSF.OwnedSFEs;
        }
    } 
}   

这是SF类型的代码。它是在 ViewModel 之外定义的。 (这会是问题所在吗?

public class SetupSF : ViewModelBase
{
    private string _iD;
    public string Id
    {
        get { return _iD; }
        set
        {
            _iD = value;
            RaisePropertyChanged(nameof(Id));
        }
    }

    private string _sfName;
    public string SFName
    {
        get { return _sfName; }
        set
        {
            _sfName = value;
            RaisePropertyChanged(nameof(SFName));
        }
    }

    public ObservableCollection<SetupSFE> OwnedSFEs { get; set; }
}

这是组合框的 XAML:

<ComboBox x:Name="ComboBox A" 
          Width="350" 
          ItemsSource="{x:Bind ViewModel.SourceForSFList}"
          SelectedItem="{x:Bind ViewModel.SelectedSF, Mode=TwoWay}"
          DisplayMemberPath="SFName"/>

<ComboBox x:Name="Comobox B"
          Width="350"
          ItemsSource="{x:Bind ViewModel.SourceForSFEList}"
          SelectedItem="{x:Bind ViewModel.SelectedSFE, Mode=TwoWay}   
          DisplayMemberPath="SFEName"/>

我相信您想将 SourceForSFEList 更改为如下所示:

private ObservableCollection<SetupSFE> _sourceForSFEList = new ObservableCollection<SetupSFE>();
public ObservableCollection<SetupSFE> SourceForSFEList
{
    get { return _sourceForSFEList; }
    set
    {
        _sourceForSFEList.Clear();
        if (value != null)
        {
            foreach (var item in value)
            {
                _sourceForSFEList.Add(item);
            }

        }
    }
}

绑定系统正在调用您的 "get" 一次,并且正在获取 _sourceForSFEList 指向的初始集合。稍后,您将 _sourceForSFEList 更改为指向另一个集合,但绑定系统对该集合一无所知,因此 UI 不会更新。绑定系统将 UI 元素绑定到 _sourceForSFEList 后,您需要更新该原始集合,而不是更改 _sourceForSFEList 的值以指向新集合。

我试图推断出您的一些原创 类。这是一个工作示例,我曾经让一个组合框的选择更新另一个组合框的选择。

   public class ViewModel
    {
        private ObservableCollection<SetupSF> _sourceForSFList = new ObservableCollection<SetupSF>();

        public ViewModel()
        {
            _sourceForSFList = new ObservableCollection<SetupSF>()
            {
                new SetupSF() { SFName = "One", OwnedSFEs = new ObservableCollection<SetupSFE> () { new SetupSFE() { SFEName = "Three" }, new SetupSFE() { SFEName = "Four" } } },
                new SetupSF() { SFName = "Two", OwnedSFEs = new ObservableCollection<SetupSFE> () { new SetupSFE() { SFEName = "Five" }, new SetupSFE() { SFEName = "Six" } } }
            };
            _sourceForSFEList = new ObservableCollection<SetupSFE>()
            {
                new SetupSFE() { SFEName = "One"},
                new SetupSFE() { SFEName = "Two"}
            };
        }

        private SetupSF _selectedSF;
        public SetupSF SelectedSF
        {
            get { return _selectedSF; }
            set
            {
                _selectedSF = value;
                if (_selectedSF != null)
                {
                    SourceForSFEList = _selectedSF.OwnedSFEs;
                }
            }
        }

        public ObservableCollection<SetupSF> SourceForSFList
        {
            get { return _sourceForSFList; }
            set
            {
                _sourceForSFList = value;
            }
        }

        private ObservableCollection<SetupSFE> _sourceForSFEList = new ObservableCollection<SetupSFE>();
        public ObservableCollection<SetupSFE> SourceForSFEList
        {
            get { return _sourceForSFEList; }
            set
            {
                _sourceForSFEList.Clear();
                if (value != null)
                {
                    foreach (var item in value)
                    {
                        _sourceForSFEList.Add(item);
                    }

                }
            }
        }

    }

    public class SetupSF
    {
        public String SFName { get; set; }
        public ObservableCollection<SetupSFE> OwnedSFEs;
    }

    public class SetupSFE
    {
        public String SFEName { get; set; }
    }

<Page
    x:Class="App7.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App7"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Page.DataContext>
        <local:ViewModel />
    </Page.DataContext>

    <StackPanel Orientation="Horizontal">
        <ComboBox x:Name="ComboBoxA" 
          Width="350" 
          ItemsSource="{Binding SourceForSFList}"
          SelectedItem="{Binding SelectedSF, Mode=TwoWay}"
          DisplayMemberPath="SFName" Margin="10"/>

        <ComboBox x:Name="ComoboxB"
          Width="350"
          ItemsSource="{Binding SourceForSFEList}"
          SelectedItem="{Binding SelectedSFE, Mode=TwoWay}"   
          DisplayMemberPath="SFEName" Margin="10"/>
    </StackPanel>
</Page>