就个人而言,我会将其保留在 viewmodel 代码中。我做了类似的事情,所以在这里,映射到你正在做的事情:
我的视图模型中有一个预先填充的项目列表。这将是 MatchTypes。
我将拥有另一个名为 CurrentMatchType 的属性,在设置时使用 INotifyPropertyChanged。
当设置 CurrentMatchType 的值时,它将调用数据源并填充视图模型上的其他两个列表。我们还有 2 个变量,称为 PouleA 和 PouleB,代表最终的团队选择。我们将调用您刚刚从服务器 TeamsA 和 TeamsB 获取的列表。两个列表的数据相同,但我会将数据源结果设置为内部值,然后将 TeamsA 设置为除 PouleB 中选择的团队之外的所有团队的列表,并将 TeamsB 的列表设置为除 PouleB 之外的所有团队的列表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);
}
}