如何使用C#生成锦标赛表的HTML表格

7

我已经卡在这个问题上三个星期了,但是我一点也搞不清楚。我的目标是去使用表格来得到下面那种输出/展示。

http://www.esl-world.net/masters/season6/hanover/sc2/playoffs/rankings/

这是一个踢球比赛的分组系统。所以我的模型如下。

public class Match{
public int id {get;set;}
public int teamid1 {get;set;}
public int teamid2 {get;set;}
public int roundnumber {get;set;}
public int winner {get;set;}
}

现在,我正在执行的操作是先循环遍历回合。例如,如果有四个回合,我会这样做:

for(int r = 1; r < bracketRounds; r++){
   for(m = 1; m < roundMatches +1; m++){
      matchGroup = "<tr><td>" + team1 + "</td></tr>"
                 + "<tr><td>vs</td></tr>"
                 + "<tr><td>" + team2 + "</td></tr>";
   }
}

但这样只会生成一个列的表格,显示所有匹配项。想知道有没有人能够帮助/指导我应该如何处理,以便我可以将后续行插入到第一行的右侧,使其具有类似括号的输出。
谢谢!

1
从他们的html代码来看... 他们是在使用一个大表格来处理所有内容。你也可以通过把多个只有一列的表格分别放在它们各自的div中,然后再使用css来定位它们到你想要的位置。 - Yaur
太棒了!艺术品,逻辑非常出色。我认为您应该先计算和检索每场比赛的获胜者信息,然后正确地应用colspan列中的数字。查看参考站点,表格设计仅与colspan有关。 - Murtaza
那其实是我做的第一件事,如果我找到了一个,我就不会问了。不过还是谢谢你提醒! - gdubs
2个回答

13

这是我的尝试。我已经测试了2、3和4轮锦标赛的代码。2轮和3轮锦标赛的输出结果如下所示:

输入图像说明


输入图像说明


我使用了你提供的相同模型来定义了一个Match类。我添加了一个Tournament类来生成测试数据。

Match.cs - 包含这些模型的类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace tournament
{
    public class Match
    {
        public int id { get; set; }
        public int teamid1 { get; set; }
        public int teamid2 { get; set; }
        public int roundnumber { get; set; }
        public int winner { get; set; }

        public Match(int id, int teamid1, int teamid2, int roundnumber, int winner)
        {
            this.id = id;
            this.teamid1 = teamid1;
            this.teamid2 = teamid2;
            this.roundnumber = roundnumber;
            this.winner = winner;
        }
    }

    public class Tournament
    {
        public SortedList<int, SortedList<int, Match>> TournamentRoundMatches { get; private set; }
        public Match ThirdPlaceMatch { get; private set; }

        public Tournament(int rounds)
        {
            this.TournamentRoundMatches = new SortedList<int, SortedList<int, Match>>();
            this.GenerateTournamentResults(rounds);
            if (rounds > 1)
            {
                this.GenerateThirdPlaceResult(rounds);
            }
        }

        public void AddMatch(Match m)
        {
            if (this.TournamentRoundMatches.ContainsKey(m.roundnumber))
            {
                if (!this.TournamentRoundMatches[m.roundnumber].ContainsKey(m.id))
                {
                    this.TournamentRoundMatches[m.roundnumber].Add(m.id, m);
                }
            }
            else
            {
                this.TournamentRoundMatches.Add(m.roundnumber, new SortedList<int, Match>());
                this.TournamentRoundMatches[m.roundnumber].Add(m.id, m);
            }
        }

        private void GenerateTournamentResults(int rounds)
        {
            Random WinnerRandomizer = new Random();

            for (int round = 1, match_id = 1; round <= rounds; round++)
            {
                int matches_in_round = 1 << (rounds - round);
                for (int round_match = 1; round_match <= matches_in_round; round_match++, match_id++)
                {
                    int team1_id;
                    int team2_id;
                    int winner;
                    if (round == 1)
                    {
                        team1_id = (match_id * 2) - 1;
                        team2_id = (match_id * 2);
                    }
                    else
                    {
                        int match1 = (match_id - (matches_in_round * 2) + (round_match - 1));
                        int match2 = match1 + 1;
                        team1_id = this.TournamentRoundMatches[round - 1][match1].winner;
                        team2_id = this.TournamentRoundMatches[round - 1][match2].winner;
                    }
                    winner = (WinnerRandomizer.Next(1, 3) == 1) ? team1_id : team2_id;
                    this.AddMatch(new Match(match_id, team1_id, team2_id, round, winner));
                }
            }
        }

        private void GenerateThirdPlaceResult(int rounds)
        {
            Random WinnerRandomizer = new Random();
            int semifinal_matchid1 = this.TournamentRoundMatches[rounds - 1].Keys.ElementAt(0);
            int semifinal_matchid2 = this.TournamentRoundMatches[rounds - 1].Keys.ElementAt(1);
            Match semifinal_1 = this.TournamentRoundMatches[rounds - 1][semifinal_matchid1];
            Match semifinal_2 = this.TournamentRoundMatches[rounds - 1][semifinal_matchid2];
            int semifinal_loser1 = (semifinal_1.winner == semifinal_1.teamid1) ? semifinal_1.teamid2 : semifinal_1.teamid1;
            int semifinal_loser2 = (semifinal_2.winner == semifinal_2.teamid1) ? semifinal_2.teamid2 : semifinal_2.teamid1;
            int third_place_winner = (WinnerRandomizer.Next(1, 3) == 1) ? semifinal_loser1 : semifinal_loser2;
            this.ThirdPlaceMatch = new Match((1 << rounds) + 1, semifinal_loser1, semifinal_loser2, 1, third_place_winner);
        }
    }
}
我使用静态方法GenerateHTMLResultsTable动态生成了原始HTML。这是仅使用<table>而不需要<div>块的方法实现的。 Program.cs是一个静态类,它初始化测试数据并生成HTML。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace tournament
{
    class Program
    {
        static string GenerateHTMLResultsTable(Tournament tournament)
        {
            int match_white_span;
            int match_span;
            int position_in_match_span;
            int column_stagger_offset;
            int effective_row;
            int col_match_num;
            int cumulative_matches;
            int effective_match_id;
            int rounds = tournament.TournamentRoundMatches.Count;
            int teams = 1 << rounds;
            int max_rows = teams << 1;
            StringBuilder HTMLTable = new StringBuilder();

            HTMLTable.AppendLine("<style type=\"text/css\">");
            HTMLTable.AppendLine("    .thd {background: rgb(220,220,220); font: bold 10pt Arial; text-align: center;}");
            HTMLTable.AppendLine("    .team {color: white; background: rgb(100,100,100); font: bold 10pt Arial; border-right: solid 2px black;}");
            HTMLTable.AppendLine("    .winner {color: white; background: rgb(60,60,60); font: bold 10pt Arial;}");
            HTMLTable.AppendLine("    .vs {font: bold 7pt Arial; border-right: solid 2px black;}");
            HTMLTable.AppendLine("    td, th {padding: 3px 15px; border-right: dotted 2px rgb(200,200,200); text-align: right;}");
            HTMLTable.AppendLine("    h1 {font: bold 14pt Arial; margin-top: 24pt;}");
            HTMLTable.AppendLine("</style>");

            HTMLTable.AppendLine("<h1>Tournament Results</h1>");
            HTMLTable.AppendLine("<table border=\"0\" cellspacing=\"0\">");
            for (int row = 0; row <= max_rows; row++)
            {
                cumulative_matches = 0;
                HTMLTable.AppendLine("    <tr>");
                for (int col = 1; col <= rounds + 1; col++)
                {
                    match_span = 1 << (col + 1);
                    match_white_span = (1 << col) - 1;
                    column_stagger_offset = match_white_span >> 1;
                    if (row == 0)
                    {
                        if (col <= rounds)
                        {
                            HTMLTable.AppendLine("        <th class=\"thd\">Round " + col + "</th>");
                        }
                        else
                        {
                            HTMLTable.AppendLine("        <th class=\"thd\">Winner</th>");
                        }
                    }
                    else if (row == 1)
                    {
                        HTMLTable.AppendLine("        <td class=\"white_span\" rowspan=\"" + (match_white_span - column_stagger_offset) + "\">&nbsp;</td>");
                    }
                    else
                    {
                        effective_row = row + column_stagger_offset;
                        if (col <= rounds)
                        {
                            position_in_match_span = effective_row % match_span;
                            position_in_match_span = (position_in_match_span == 0) ? match_span : position_in_match_span;
                            col_match_num = (effective_row / match_span) + ((position_in_match_span < match_span) ? 1 : 0);
                            effective_match_id = cumulative_matches + col_match_num;
                            if ((position_in_match_span == 1) && (effective_row % match_span == position_in_match_span))
                            {
                                HTMLTable.AppendLine("        <td class=\"white_span\" rowspan=\"" + match_white_span + "\">&nbsp;</td>");
                            }
                            else if ((position_in_match_span == (match_span >> 1)) && (effective_row % match_span == position_in_match_span))
                            {
                                HTMLTable.AppendLine("        <td class=\"team\">Team " + tournament.TournamentRoundMatches[col][effective_match_id].teamid1 + "</td>");
                            }
                            else if ((position_in_match_span == ((match_span >> 1) + 1)) && (effective_row % match_span == position_in_match_span))
                            {
                                HTMLTable.AppendLine("        <td class=\"vs\" rowspan=\"" + match_white_span + "\">VS</td>");
                            }
                            else if ((position_in_match_span == match_span) && (effective_row % match_span == 0))
                            {
                                HTMLTable.AppendLine("        <td class=\"team\">Team " + tournament.TournamentRoundMatches[col][effective_match_id].teamid2 + "</td>");
                            }
                        }
                        else
                        {
                            if (row == column_stagger_offset + 2)
                            {
                                HTMLTable.AppendLine("        <td class=\"winner\">Team " + tournament.TournamentRoundMatches[rounds][cumulative_matches].winner + "</td>");
                            }
                            else if (row == column_stagger_offset + 3)
                            {
                                HTMLTable.AppendLine("        <td class=\"white_span\" rowspan=\"" + (match_white_span - column_stagger_offset) + "\">&nbsp;</td>");
                            }
                        }
                    }
                    if (col <= rounds)
                    {
                        cumulative_matches += tournament.TournamentRoundMatches[col].Count;
                    }
                }
                HTMLTable.AppendLine("    </tr>");
            }
            HTMLTable.AppendLine("</table>");

            HTMLTable.AppendLine("<h1>Third Place Results</h1>");
            HTMLTable.AppendLine("<table border=\"0\" cellspacing=\"0\">");
            HTMLTable.AppendLine("    <tr>");
            HTMLTable.AppendLine("        <th class=\"thd\">Round 1</th>");
            HTMLTable.AppendLine("        <th class=\"thd\">Third Place</th>");
            HTMLTable.AppendLine("    </tr>");
            HTMLTable.AppendLine("    <tr>");
            HTMLTable.AppendLine("        <td class=\"white_span\">&nbsp;</td>");
            HTMLTable.AppendLine("        <td class=\"white_span\" rowspan=\"2\">&nbsp;</td>");
            HTMLTable.AppendLine("    </tr>");
            HTMLTable.AppendLine("    <tr>");
            HTMLTable.AppendLine("        <td class=\"team\">Team " + tournament.ThirdPlaceMatch.teamid1 + "</td>");
            HTMLTable.AppendLine("    </tr>");
            HTMLTable.AppendLine("    <tr>");
            HTMLTable.AppendLine("        <td class=\"vs\">VS</td>");
            HTMLTable.AppendLine("        <td class=\"winner\">Team " + tournament.ThirdPlaceMatch.winner + "</td>");
            HTMLTable.AppendLine("    </tr>");
            HTMLTable.AppendLine("    <tr>");
            HTMLTable.AppendLine("        <td class=\"team\">Team " + tournament.ThirdPlaceMatch.teamid2 + "</td>");
            HTMLTable.AppendLine("        <td class=\"white_span\">&nbsp;</td>");
            HTMLTable.AppendLine("    </tr>");
            HTMLTable.AppendLine("</table>");
            return HTMLTable.ToString();
        }

        static void Main(string[] args)
        {
            Tournament Test3RoundTournament = new Tournament(3);
            Tournament Test2RoundTournament = new Tournament(2);
            File.WriteAllText(@"C:\Tournament\results.html", GenerateHTMLResultsTable(Test2RoundTournament));
            File.WriteAllText(@"C:\Tournament\results.html", GenerateHTMLResultsTable(Test3RoundTournament));
            Console.ReadLine();
        }
    }
}

更新

HTML表格生成参数的解释

enter image description here

如您所见,column_stagger_offset表示每列向上移动的量,以使它们按预期对齐。 effective_row实际上是特定表格单元格在没有垂直偏移的情况下应该位于的位置。 知道effective_rowposition_in_match_span有助于确定该单元格中需要显示什么(空白、team1、team2或vs.)。

正如您已经注意到的,我正在逐行迭代列。考虑到HTML表格也是这样构建的,即创建行,添加单元格...创建行,添加单元格...等等,这似乎是最自然的方法。


哇,非常感谢!!! 很抱歉回复晚了,我之前有些困惑。不过,我有几个问题。看起来你是按列而不是按行处理的?此外,我试图理解stagger_offset和effective_row的用途是什么? - gdubs
@gdubs 我稍后会解释这些内容。如果我只用文字来解释,我不认为它会很清楚。我会编辑答案并附上一些图片,解释这些变量的含义。 - torrential coding

1
我们可以通过动态添加表行和表格单元格,使用System.Web.UI.WebControls.Table来实现这一点。

类文件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for Matches
/// </summary>

    public class Rounds
    {
        public int RoundNumber{get;set;}
        public List<Match> Matches{get;set;}

        public Rounds(int number, List<Match> matches)
        {
            this.RoundNumber = number;
            this.Matches = matches;
        }
    }

    public class Match
    {
        public int MatchId{get;set;}
        public Team Team1{get;set;}
        public Team Team2 {get; set;}
        public Team WinningTeam { get; set; }

        public Match(int id, Team t1, Team t2) :this (id, t1, t2, null)
        {

        }

        public Match(int id, Team t1, Team t2, Team t3)
        {
            this.MatchId = id;
            this.Team1 = t1;
            this.Team2 = t2;
            this.WinningTeam = t3;
        }
    }

    public class Team
    {
        public int TeamId {get;set;}
        public string TeamName {get;set;}

        public Team(int id, string name)
        {
            this.TeamId = id;
            this.TeamName = name;
        }
    }

.aspx.cs文件 - 我们需要在.aspx文件中添加一个div控件。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Test : System.Web.UI.Page
{
    List<Rounds> rounds = new List<Rounds>();
    protected void Page_Load(object sender, EventArgs e)
    {
        ShowRoundMatchesUsingTable();
    }

    private List<Rounds> GetRoundMatchesDetails()
    {
        List<Team> teamList = new List<Team>();
        teamList.Add(new Team(1, "Arcenal"));
        teamList.Add(new Team(2, "Barsa"));
        teamList.Add(new Team(3, "Manchester"));
        teamList.Add(new Team(4, "Black Burn"));
        teamList.Add(new Team(5, "Ferrari"));
        teamList.Add(new Team(6, "Adidas"));
        teamList.Add(new Team(7, "Reebock"));
        teamList.Add(new Team(8, "Nike"));

        List<Match> matchList1 = new List<Match>();
        matchList1.Add(new Match(1, teamList.Find(lst => lst.TeamName == "Arcenal"), teamList.Find(lst => lst.TeamName == "Barsa")));
        matchList1.Add(new Match(1, teamList.Find(lst => lst.TeamName == "Manchester"), teamList.Find(lst => lst.TeamName == "Black Burn")));
        matchList1.Add(new Match(1, teamList.Find(lst => lst.TeamName == "Ferrari"), teamList.Find(lst => lst.TeamName == "Adidas")));
        matchList1.Add(new Match(1, teamList.Find(lst => lst.TeamName == "Reebock"), teamList.Find(lst => lst.TeamName == "Nike")));

        List<Match> matchList2 = new List<Match>();
        matchList2.Add(new Match(2, teamList.Find(lst => lst.TeamName == "Arcenal"), teamList.Find(lst => lst.TeamName == "Manchester")));
        matchList2.Add(new Match(2, teamList.Find(lst => lst.TeamName == "Adidas"), teamList.Find(lst => lst.TeamName == "Nike")));

        List<Rounds> rounds = new List<Rounds>();

        rounds.Add(new Rounds(1, matchList1));
        rounds.Add(new Rounds(2, matchList2));

        return rounds;
    }

    private void ShowRoundMatchesUsingTable()
    {
        IEnumerable<Rounds> roundsList = GetRoundMatchesDetails();

        if (roundsList == null || roundsList.Count() == 0) return;

        Table tbl = new Table();

        TableRow trHeaderRow = new TableRow();
        TableRow trDetailRow = new TableRow();
        TableCell tcDetails = new TableCell();

        foreach (Rounds round in roundsList)
        {
            TableHeaderCell th = new TableHeaderCell();
            th.Text = "Round : " + round.RoundNumber ;
            trHeaderRow.Cells.Add(th);

            if (round.Matches != null && round.Matches.Count > 0)
            {
                tcDetails = new TableCell();
                trDetailRow.Cells.Add(tcDetails);
            }

            foreach (Match m in round.Matches)
            {
                Table dtlTable = new Table();
                tcDetails.Controls.Add(dtlTable);

                TableRow tr1 = new TableRow();
                TableCell tc = new TableCell();
                tc.Text = m.Team1.TeamName;
                tr1.Cells.Add(tc);
                dtlTable.Rows.Add(tr1);

                tr1 = new TableRow();
                tc = new TableCell();
                tc.Text = "Vs";
                tr1.Cells.Add(tc);
                dtlTable.Rows.Add(tr1);

                tr1 = new TableRow();
                tc = new TableCell();
                tc.Text = m.Team2.TeamName;
                tr1.Cells.Add(tc);
                dtlTable.Rows.Add(tr1);
            }
        }

        tbl.Rows.Add(trHeaderRow);
        tbl.Rows.Add(trDetailRow);
        div.Controls.Add(tbl);
    }
}

嗯,有趣,我从未想过这个!让我看看能否在MVC上复制这个! - gdubs
@Shamjith HaridasanпјҢжҲ‘и®ӨдёәдҪ зҡ„ShowRoundMatchesUsingTable()еҮҪж•°дёҚдјҡеғҸOPй“ҫжҺҘйЎөйқўдёҠжҳҫзӨәзҡ„йӮЈж ·еҜ№йҪҗжҜ”иөӣгҖӮе®ғд№ҹдёҚдјҡжҢүз…§OPйў„жңҹзҡ„жӢ¬еҸ·зі»з»ҹиҝӣиЎҢж“ҚдҪңгҖӮеҰӮжһңжҲ‘й”ҷдәҶпјҢиҜ·зә жӯЈжҲ‘гҖӮ - torrential coding
是的,这就是我目前遇到的难题。看起来为MVC创建一个单独的类是正确的方法,但是按照我想要的方式对齐它正在变得困难。 - gdubs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接