【问题标题】:Show combobox items depending on a value from a different combobox根据来自不同组合框的值显示组合框项目
【发布时间】:2012-05-15 07:02:10
【问题描述】:

我正在尝试创建一个小型应用程序,我可以在其中为即将到来的欧洲足球锦标赛打球。

为此,我当然需要添加匹配项。

我希望有 3 个组合框,其中第一个由它的匹配类型设置(Poule A、Poule B 等)。设置该组合框后,我希望接下来的两个组合框仅显示这些 poules 中的团队。

我相信这可以使用转换器来完成,但我似乎无法让它工作..或者有更好的方法吗?

当前代码:

<ComboBox ItemsSource="{Binding MatchTypes}"
                        DisplayMemberPath="TypeName"
                        Grid.Row="1" />

<ComboBox ItemsSource="{Binding Teams}"
                        DisplayMemberPath="TeamName"
                        Grid.Column="1"
                        Grid.Row="1" />

<ComboBox ItemsSource="{Binding Teams}"
                        DisplayMemberPath="TeamName"
                        Grid.Column="2"
                        Grid.Row="1" />

是否有一种简单的方法(linq?)来查询最后两个组合框,只查询在第一个组合框中选择的 poule 中的团队?

如果可能的话,我更愿意将其保留在视图模型之外并使用转换器或类似的东西。

【问题讨论】:

    标签: c# silverlight combobox filter converter


    【解决方案1】:

    就我个人而言,我会将其保留在视图模型代码中。我做过类似的事情,所以在这里,映射到你正在做的事情:

    • 我的视图模型中有一个预先填充的项目列表。这将是 MatchTypes。

    • 我会有另一个名为 CurrentMatchType 的属性,在设置时使用 INotifyPropertyChanged。

    • 设置 CurrentMatchType 的值后,它将调用数据源并填充视图模型上的其他两个列表。我们还有 2 个变量,称为 PouleA 和 PouleB,代表最终的团队选择。我们将调用您刚刚从服务器 TeamsA 和 TeamsB 获取的列表。两个列表的数据相同,但我会将数据源结果设置为内部值,然后将 TeamsA 设置为除 PouleB 中选择的团队之外的所有团队的列表,并将 TeamsB 的列表设置为除 PouleB 之外的所有团队的列表PouleA中的那些。这样一来,一个团队无法单独匹配。

    • 我忘记的最后一件事:在 PouleA 和 PouleB 的设置器上,您将运行与上述相同的代码来过滤可用的团队,因此也排除了对面的团队。由于 INPC 连接到所有内容,您的组合框都会自动更改。

    • 当我从数据源抓取数据时,我会公开一个属性以让 BusyIndi​​cator 接管屏幕,因此在抓取数据之前无法触摸任何内容。

    我的阵营认为尝试将转换器用于此类事情会增加不必要的挫败感。如果您不想将它添加到您的视图模型中,因为您在不同的地方重复使用它,那么没有什么能阻止您创建一个将旧视图模型作为属性公开的新视图模型。

    伪代码

    using System;
    
    /* In your model... */
    
    public sealed class MatchType
    {
        public string Name { get; internal set; }
        public string Description { get; internal set; }
        public int ID { get; internal set; }
    }
    
    public sealed class Team
    {
        public string Name { get; set; }
        public MatchType MatchType { get; set; }
        public int? MatchTypeID { get; set; }
        public int ID { get; set; }
    }
    
    /* In your viewmodel... */
    
    public sealed class TeamSelection
    {
    
        // These two should be INotifyPropertyChanged, shortened for this example.
        public MatchType[] MatchTypes { get; private set; }
        public Team[] TeamsA { get; private set; }
        public Team[] TeamsB { get; private set; }
    
        private Team[] teams = null;
        MatchType matchType = null;
        public MatchType SelectedMatchType {
            get { return matchType; }
            set
            {
                if (value != null)
                    matchType = value;
                else if (MatchTypes != null && MatchTypes.Length > 0)
                    matchType = MatchTypes[0];
                else
                    return;
                PropertyHasChanged(() => SelectedMatchType);
                PopulateTeams();
            }
        }
    
        Team teamA;
        Team teamB;
    
        public Team SelectedTeamA 
        {
            get { return teamA; }
            set
            {
                if (teamA.ID == teamB.ID)
                    // Alternatively, set a flag and stop execution.
                    throw new InvalidOperationException("The same team cannot be selected.");
                teamA = value;
                PopulateTeams();
                PropertyHasChanged(() => SelectedTeamA);
            }
        }
    
        public Team SelectedTeamB 
        {
            get { return teamB; }
            set
            {
                if (teamA.ID == teamB.ID)
                    // Alternatively, set a flag and stop execution.
                    throw new InvalidOperationException("The same team cannot be selected.");
                teamB = value;
                PopulateTeams();
                PropertyHasChanged(() => SelectedTeamB);
            }
        }
    
        /// <summary>
        /// This can be done on your model, or what I do is pass it to 
        /// an intermediary class, then that sets the busy status to
        /// a BusyIndicator set as the visual root of the application.
        /// </summary>
        public bool IsBusy { get; private set; }
        public string IsBusyDoingWhat { get; private set; }
    
        public TeamSelection()
        {
            // Call out to DB for the match types, setting busy status
            var wcf = new WcfService();
            wcf.GetMatchTypes(response => 
            {
                wcf.GetMatchTypesForTeam(MatchType, response2 =>
                {
                    teams = response.Value.ToArray();
                    MatchTypes = response2.Value.ToArray();
                    MatchType = MatchTypes[0];
                    PopulateTeams();
                });
            });
        }
    
        void PopulateTeams()
        {
            if (MatchType == null)
                return;
            var op = teams.Where(t => t.MatchTypeID == MatchType.ID);
            if (SelectedTeamA != null)
                TeamsB = op.Where(t => t.ID != SelectedTeamA.ID).OrderBy(t => t.Name);
            else
                TeamsB = op.OrderBy(t => t.Name);
            if (SelectedTeamB != null)
                TeamsA = op.Where(t => t.ID != SelectedTeamB.ID).OrderBy(t => t.Name);
            else
                TeamsA = op.OrderBy(t => t.Name);
        }
    
    }
    

    【讨论】:

    • 我完全同意,尝试在视图模型上进行数据操作。
    • 感谢您的详细解答。我相信我可以做到这一点。
    猜你喜欢
    • 2013-03-18
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多