根据不同组合框中的值显示组合框项
本文关键字:组合 显示 | 更新日期: 2023-09-27 18:33:29
我正在尝试创建一个小应用程序,我可以在其中为即将到来的欧洲足球锦标赛做一个球。
为此,我当然需要添加匹配项。
我希望有 3 个组合框,其中第一个由匹配类型(保尔 A、保尔 B 等(设置。设置该组合框后,我希望接下来的两个组合框仅显示这些滚球中的球队。
我相信这可以使用转换器来完成,但我似乎无法让它工作.. 或者有更好的方法吗?
当前代码:
<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?(来查询最后两个组合框,只查询第一个组合框中选择的球队?
如果可能的话,我更喜欢将其排除在视图模型之外,并使用转换器或类似的东西。
就个人而言,我会将其保留在视图模型代码中。我已经做了类似的事情,所以在这里,映射到你正在做的事情:
-
我的视图模型中有一个预填充的项目列表。这将是匹配类型。
-
我会有另一个名为 CurrentMatchType 的属性,在设置时使用 INotifyPropertyChanged。
-
设置 CurrentMatchType 的值后,它将调用数据源并填充视图模型上的其他两个列表。我们还有 2 个变量,称为 PouleA 和 PouleB,代表最终的团队选择。我们将您刚刚从服务器中获取的列表称为 TeamsA 和 TeamsB。两个列表的数据相同,但我会将数据源结果设置为内部值,然后将 TeamsA 设置为除 PouleB 中选择的球队之外的所有球队的列表,并将 TeamsB 列表设置为除 PouleA 中选择的球队之外的所有球队的列表。这样,一个团队就无法与自己匹敌。
-
我忘记了最后一件事:在 PouleA 和 PouleB 的二传手上,您将运行与上面相同的代码来过滤可用的球队,以便排除相反的球队。由于INPC与所有内容挂钩,因此您的组合框将自动更改。
-
当我从数据源获取数据时,我公开一个属性,让 BusyIndicator 接管屏幕,以便在完成数据抓取之前不能触摸任何内容。
我在阵营中认为尝试使用转换器来处理这样的事情会增加不必要的挫败感。如果您不想将其添加到视图模型中,因为您要在不同位置重用它,那么没有什么可以阻止您创建一个新的视图模型,将旧视图模型公开为属性。
伪代码
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);
}
}