Rendering a generated table with TableLayoutPanel taking too long to finish - c#

My program is pretty straight forward in concept - it allows a user to take scores during bowling tournaments, as well as showing the players the scores through a scoreboard.
There's a score sheet form in which they enter scores, and a scoreboard form that shows the scores to the players, by division. The scoreboard is run in a different thread than the main program.
The scoreboard is comprised of a TableLayoutPanel which I manipulate programmatically to represent a table of the scores to show. My issue with this is that it takes a long time (especially for a long list of players) for the table to render. The user experience of watching the table render itself leaves to be desired as well.
I tested the speed of rendering textboxes, labels, and picture boxes to lessen the load; textboxes won, so I changed the score labels to textboxes... but it's still not enough.
It's a lot to look through, but if anyone has any idea how I could further speed up the rendering of the scoreboard, I'd be all ears/eyes.
Here's my process broken down.
The calling method (called every 15 seconds by a timer):
private void switchBoard()
{
night = nights.GetNight(nightID);
NightDay = night.Night_Date.ToString("ddd");
//set the id of the division to show
dtDivisions = scoreBoard.roll_display(dtDivisions);
//get the row that is set to show
DataRow[] drs = dtDivisions.Select("showing = 1");
DataRow dr = drs[0];
//update the title
lbl_title.Top = 30;
lbl_title.Text = (string)dr["title"] + "'s Qualifying - " + NightDay;
lbl_title.Width = this.Width;
lbl_title.TextAlign = ContentAlignment.MiddleCenter;
//SET UP THE TABLE
//get number of columns (games) for selected night
int Cols = games.GetCountGamesForTourNightByDivision(tourID, nightID, scoreBoard.ShowDivision) + 3; //ACCOUNT FOR HEADER COLS, RANK AND TOTALS
//get number of rows (players) for selected night
int Rows = players.GetCountPlayersForTourNightByDivision(TourID, nightID, scoreBoard.ShowDivision) + 1; //ACCOUNT FOR HEADER ROWS
//generate the table
GenerateTable(Cols, Rows);
//generate the headers
GenerateHeaders(tourID, nightID);
//fill in the scores
GenerateScoreLabels(tourID, nightID, scoreBoard.ShowDivision);
}
Generating the table:
private void GenerateTable(int columnCount, int rowCount)
{
//Clear out the existing controls, we are generating a new table layout
this.tblPnlScoreboard.Controls.Clear();
//Clear out the existing row and column styles
this.tblPnlScoreboard.ColumnStyles.Clear();
this.tblPnlScoreboard.RowStyles.Clear();
//setting up the row and column counts
this.tblPnlScoreboard.ColumnCount = columnCount;
this.tblPnlScoreboard.RowCount = rowCount;
for (int x = 0; x < columnCount; x++)
{
//add a column
if(x==0) //ranking column
{
this.tblPnlScoreboard.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute,30));
}
else if(x==1) //names
{
this.tblPnlScoreboard.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
}
else if(x==columnCount-1) //totals
{
this.tblPnlScoreboard.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
}
else //games
{
this.tblPnlScoreboard.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, (this.tblPnlScoreboard.Width - 130) / columnCount));
}
for (int y = 0; y < rowCount; y++)
{
//add rows. Only do this once, when creating the first column
if (x == 0)
{
if(y==0)
{
this.tblPnlScoreboard.RowStyles.Add(new RowStyle(SizeType.Absolute, 50));
}
else
{
this.tblPnlScoreboard.RowStyles.Add(new RowStyle(SizeType.AutoSize));
}
}
}
}
}
Generating the headers:
private void GenerateHeaders(int TourID, int NightID)
{
//get the players to display
DataTable dtPlayers = players.GetPlayersForTourNightByDivision(tourID, nightID, scoreBoard.ShowDivision);
int Row = 1; //0 is the header row for Games and so on
foreach (DataRow dr in dtPlayers.Rows)
{
//create the label
Label lblPlayer = new Label();
lblPlayer.Name = dr["ID"].ToString(); //name is the ID of the player
lblPlayer.Text = dr["player_name"].ToString(); //the text is the name of the player
lblPlayer.BackColor = Color.Transparent;
lblPlayer.Font = new Font("Microsoft Sans Serif", 25, FontStyle.Bold);
lblPlayer.TextAlign = ContentAlignment.MiddleLeft;
lblPlayer.AutoSize = true;
lblPlayer.Height = tblPnlScoreboard.GetRowHeights()[Row];
//add the label to the table
this.tblPnlScoreboard.Controls.Add(lblPlayer, 1, Row);
//create the Total label
Label lblTotal = new Label();
lblTotal.Name = "lbl_total"; //name is arbitrary in this context
lblTotal.Text = dr["Total"].ToString(); //the text is the total
lblTotal.BackColor = Color.Transparent;
lblTotal.Font = new Font("Microsoft Sans Serif", 25, FontStyle.Bold);
lblTotal.TextAlign = ContentAlignment.MiddleLeft;
lblTotal.AutoSize = true;
lblTotal.Height = tblPnlScoreboard.GetRowHeights()[Row];
//add the label to the table
this.tblPnlScoreboard.Controls.Add(lblTotal, tblPnlScoreboard.ColumnCount, Row);
//increment the row index
Row++;
}
//totals column
Label lblTotals = new Label();
//lblTotals.Width = this.tblPnlScoreboard.GetColumnWidths()[this.tblPnlScoreboard.ColumnCount - 1];
lblTotals.Height = tblPnlScoreboard.GetRowHeights()[0];
lblTotals.Name = "lbl_total"; //name is the ID of the Game
lblTotals.Text = "Totals"; //text is the display name of the Game
lblTotals.BackColor = Color.Transparent;
lblTotals.ForeColor = Color.White;
lblTotals.Font = new Font("Microsoft Sans Serif", 25, FontStyle.Bold);
lblTotals.TextAlign = ContentAlignment.MiddleCenter;
lblTotals.AutoSize = true;
lblTotals.Anchor = (AnchorStyles.None);
//add the label to the table
this.tblPnlScoreboard.Controls.Add(lblTotals, this.tblPnlScoreboard.ColumnCount-1, 0);
//get the games to display
DataTable dtGames = games.GetGamesForTourNightByDivision(tourID, nightID, scoreBoard.ShowDivision);
int Col = 2; //0 is the header column for rank, 1 is the header col for Players
foreach (DataRow dr in dtGames.Rows)
{
//create the label
Label lblGame = new Label();
lblGame.Width = this.tblPnlScoreboard.GetColumnWidths()[Col];
lblGame.Height = tblPnlScoreboard.GetRowHeights()[0];
lblGame.Name = dr["ID"].ToString(); //name is the ID of the Game
lblGame.Text = dr["disp_name"].ToString().Replace("Game ", ""); //text is the display name of the Game
lblGame.BackColor = Color.Transparent;
lblGame.ForeColor = Color.White;
lblGame.Font = new Font("Microsoft Sans Serif", 25, FontStyle.Bold);
lblGame.TextAlign = ContentAlignment.MiddleCenter;
lblGame.Anchor = (AnchorStyles.None);
//add the label to the table
this.tblPnlScoreboard.Controls.Add(lblGame, Col, 0);
//increment the column index
Col++;
}
}
Finally, generating the scores:
private void GenerateScoreLabels(int TourID, int NightID, int DivID)
{
//get the id of the playergames record
//expl: each player/game pair has a unique ID - these IDs will be used to update the scores
Players players = new Players();
DataTable dtScores = players.GetPlayerGamesIDsForTourNightByDivision(TourID, NightID, scoreBoard.ShowDivision);
Divisions Divs = new Divisions();
DataTable dtColors = Divs.GetDivisionScoreboardColors(DivID);
foreach (DataRow dr in dtScores.Rows)
{
//find the coordinates in the table, where the textbox should be added
int col = FindX((int)dr["fk_game_id"]);
int row = FindY((int)dr["fk_player_id"]);
if (col > 0 && row > 0)
{
TextBox txt_score = new TextBox();
txt_score.Name = dr["ID"].ToString(); //name of the control is the player/game ID
txt_score.Text = dr["score"].ToString(); //the text in the control is the score
txt_score.ForeColor = Color.Black;
txt_score.Font = new Font("Microsoft Sans Serif", 25, FontStyle.Bold);
txt_score.Width = this.tblPnlScoreboard.GetColumnWidths()[col];
txt_score.Height = tblPnlScoreboard.GetRowHeights()[0];
if(row % 2 == 0)
{
txt_score.BackColor = Color.FromArgb((int)dtColors.Rows[0]["sb_even_row_color"]);
}
else
{
txt_score.BackColor = Color.FromArgb((int)dtColors.Rows[0]["sb_odd_row_color"]);
}
txt_score.BorderStyle = BorderStyle.None;
txt_score.TextAlign = HorizontalAlignment.Center;
txt_score.Anchor = (AnchorStyles.Top);
this.tblPnlScoreboard.Controls.Add(txt_score, col, row);
//start the switchboard timer
ttmr_switch.Enabled = true;
}
}
}
On the CellPaint event of the TableLayoutPanel, I have these processes:
private void tblPnlScoreboard_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle r = e.CellBounds;
SolidBrush sb = GetBrushFor(e.Row, e.Column, scoreBoard.ShowDivision);
g.FillRectangle(sb, r);
sb.Dispose();
}
Selection of Colors:
private SolidBrush GetBrushFor(int row, int column, int DivID)
{
DataTable dt_colors = divisions.GetDivisionScoreboardColors(DivID);
if (row == 0)
{ //column headers
SolidBrush brush = new SolidBrush(Color.FromArgb((int)dt_colors.Rows[0]["sb_column_header_color"]));
return brush;
}
else
{
if(row % 2 == 0) //even row
{
SolidBrush brush = new SolidBrush(Color.FromArgb((int)dt_colors.Rows[0]["sb_even_row_color"]));
return brush;
}
else //odd row
{
SolidBrush brush = new SolidBrush(Color.FromArgb((int)dt_colors.Rows[0]["sb_odd_row_color"]));
return brush;
}
}
}

Some people suggested you to use a "proper technology". I would rather say "use properly the technology". Even this weird (sorry) design/implementation choice can be made to work much faster, as shown in the code below, which as you may see is handling rebuilding a table containing 100 rows x 10 columns 10 times per sec - not a big deal compared to professional grids, but far from the original implementation.
Key points:
1. Enclose table rebuild with Suspend/ResumeLayout to avoid intensive recalculations during the process.
2. Use custom double buffered TableLayoutPanel to avoid flickering.
3. Custom paint the data cells to avoid allocating a lot of controls.
Since essential data related parts are missing in the code you gave us, I can't provide you exactly the same working code. Hope you can recognize and map it to your stuff.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace Tests
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ScoreBoardForm { WindowState = FormWindowState.Maximized });
}
}
class ScoreBoardForm : Form
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
players = new List<Player>();
for (int i = 0; i < 100; i++)
players.Add(new Player { ID = i + 1, Name = "P" + (i + 1), Total = random.Next(1000) });
games = new List<Game>();
for (int i = 0; i < 10; i++)
games.Add(new Game { ID = i + 1, Name = "G" + (i + 1) });
scoreBoardTable = new ScoreBoardTable { Dock = DockStyle.Fill, Parent = this };
scoreBoardTable.Bounds = this.DisplayRectangle;
UpdateScoreBoard();
scoreBoardTable.CellPaint += OnScoreBoardTableCellPaint;
updateTimer = new Timer { Interval = 100 };
updateTimer.Tick += (_sender, _e) => UpdateScoreBoard();
updateTimer.Start();
}
private void OnScoreBoardTableCellPaint(object sender, TableLayoutCellPaintEventArgs e)
{
int playerIndex = e.Row - 1, gameIndex = e.Column - 2;
if (playerIndex >= 0 && playerIndex < players.Count && gameIndex >= 0 && gameIndex < games.Count)
{
using (var br = new SolidBrush(GetBackColor(e.Row)))
e.Graphics.FillRectangle(br, e.CellBounds);
var score = GetScore(players[playerIndex], games[gameIndex]);
var sf = new StringFormat { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Center };
e.Graphics.DrawString(score.ToString(), defaultCellFont, Brushes.Black, e.CellBounds, sf);
}
}
private int GetScore(Player player, Game game)
{
return random.Next(10000);
}
class ScoreBoardTable : TableLayoutPanel
{
public ScoreBoardTable() { DoubleBuffered = AutoScroll = true; }
}
TableLayoutPanel scoreBoardTable;
Timer updateTimer;
List<Player> players;
List<Game> games;
Random random = new Random();
class Player
{
public int ID;
public string Name;
public int Total;
}
class Game
{
public int ID;
public string Name;
}
private void UpdateScoreBoard()
{
scoreBoardTable.SuspendLayout();
GenerateTable(games.Count + 3, players.Count + 1);
GenerateHeaderCells();
// Custom cell paint is much faster, but requires a good data model.
// If you uncomment the following line, make sure to get rid of CellPaint.
//GenerateScoreCells();
scoreBoardTable.ResumeLayout(true);
}
private void GenerateTable(int columnCount, int rowCount)
{
scoreBoardTable.Controls.Clear();
scoreBoardTable.ColumnStyles.Clear();
scoreBoardTable.RowStyles.Clear();
scoreBoardTable.ColumnCount = columnCount;
scoreBoardTable.RowCount = rowCount;
// Columns
// Ranking
scoreBoardTable.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 30));
// Name
scoreBoardTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
// Games
var percent = (columnCount - 3) / (float)columnCount;
for (int col = 2; col < columnCount - 1; col++)
scoreBoardTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, percent));
// Totals
scoreBoardTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
// Rows
// Header
scoreBoardTable.RowStyles.Add(new RowStyle(SizeType.Absolute, 50));
// Players
for (int row = 1; row < rowCount; row++)
scoreBoardTable.RowStyles.Add(new RowStyle(SizeType.AutoSize));
}
private void GenerateHeaderCells()
{
Color backColor = Color.DarkGray, foreColor;
int row, col;
// Header
row = 0;
foreColor = Color.White;
col = 0;
AddCell(row, col++, "rank", "", foreColor, backColor);
AddCell(row, col++, "playerName", "Player", foreColor, backColor);
foreach (var game in games)
AddCell(row, col++, "gameName" + game.ID, game.Name, foreColor, backColor);
AddCell(row, col, "totalColumn", "Totals", foreColor, backColor);
// Rows
foreColor = Color.Black;
row++;
foreach (var player in players)
{
backColor = GetBackColor(row);
AddCell(row, 0, "playerRank_" + player.ID, "", foreColor, backColor, ContentAlignment.MiddleLeft);
AddCell(row, 1, "playerName_" + player.ID, player.Name, foreColor, backColor, ContentAlignment.MiddleLeft);
AddCell(row, scoreBoardTable.ColumnCount, "playerTotal_" + player.ID, player.Total.ToString(), foreColor, backColor, ContentAlignment.MiddleRight);
row++;
}
}
private void GenerateScoreCells()
{
var foreColor = Color.Black;
int row = 1;
foreach (var player in players)
{
var backColor = GetBackColor(row);
int col = 2;
foreach (var game in games)
{
var score = GetScore(player, game);
AddCell(row, col, "score_" + player.ID + "_" + game.ID, score.ToString(), foreColor, backColor, ContentAlignment.MiddleRight, false);
col++;
}
row++;
}
}
static readonly Font defaultCellFont = new Font("Microsoft Sans Serif", 25, FontStyle.Bold);
private Label AddCell(int row, int col, string name, string text, Color foreColor, Color backColor, ContentAlignment textAlign = ContentAlignment.MiddleCenter, bool autoSize = true)
{
var label = new Label();
label.Name = name;
label.Text = text;
label.BackColor = backColor;
label.ForeColor = foreColor;
label.Font = defaultCellFont;
label.TextAlign = textAlign;
label.AutoSize = autoSize;
label.Margin = new Padding(0);
label.Dock = DockStyle.Fill;
scoreBoardTable.Controls.Add(label, col, row);
return label;
}
static Color GetBackColor(int row)
{
if (row % 2 == 0) //even row
return Color.Yellow;
else //odd row
return Color.LightGreen;
}
}
}
EDIT And here is equivalent implementation using DataGridView (note that now the number of rows (players) are ten times more at the same refresh rate):
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace Tests
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ScoreBoardForm { WindowState = FormWindowState.Maximized });
}
}
class ScoreBoardForm : Form
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
players = new List<Player>();
for (int i = 0; i < 1000; i++)
players.Add(new Player { ID = i + 1, Name = "P" + (i + 1), Total = random.Next(1000) });
games = new List<Game>();
for (int i = 0; i < 10; i++)
games.Add(new Game { ID = i + 1, Name = "G" + (i + 1) });
InitScoreBoard();
UpdateScoreBoard();
updateTimer = new Timer { Interval = 100 };
updateTimer.Tick += (_sender, _e) => UpdateScoreBoard();
updateTimer.Start();
}
DataGridView scoreBoardTable;
Timer updateTimer;
List<Player> players;
List<Game> games;
Random random = new Random();
class Player
{
public int ID;
public string Name;
public int Total;
}
class Game
{
public int ID;
public string Name;
}
private int GetScore(Player player, Game game)
{
return random.Next(10000);
}
void InitScoreBoard()
{
scoreBoardTable = new DataGridView { Dock = DockStyle.Fill, Parent = this };
scoreBoardTable.Font = new Font("Microsoft Sans Serif", 25, FontStyle.Bold);
scoreBoardTable.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
scoreBoardTable.MultiSelect = false;
scoreBoardTable.CellBorderStyle = DataGridViewCellBorderStyle.None;
scoreBoardTable.BackgroundColor = Color.Honeydew;
scoreBoardTable.ForeColor = Color.Black;
scoreBoardTable.AllowUserToAddRows = scoreBoardTable.AllowUserToDeleteRows = scoreBoardTable.AllowUserToOrderColumns = scoreBoardTable.AllowUserToResizeRows = false;
scoreBoardTable.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
scoreBoardTable.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
scoreBoardTable.RowHeadersVisible = false;
scoreBoardTable.EnableHeadersVisualStyles = false;
var style = scoreBoardTable.DefaultCellStyle;
style.SelectionForeColor = style.SelectionBackColor = Color.Empty;
style = scoreBoardTable.ColumnHeadersDefaultCellStyle;
style.SelectionForeColor = style.SelectionBackColor = Color.Empty;
style.BackColor = Color.Navy;
style.ForeColor = Color.White;
style = scoreBoardTable.RowHeadersDefaultCellStyle;
style.SelectionForeColor = style.SelectionBackColor = Color.Empty;
style = scoreBoardTable.RowsDefaultCellStyle;
style.SelectionForeColor = style.ForeColor = Color.Black;
style.SelectionBackColor = style.BackColor = Color.Yellow;
style = scoreBoardTable.AlternatingRowsDefaultCellStyle;
style.SelectionForeColor = style.ForeColor = Color.Black;
style.SelectionBackColor = style.BackColor = Color.LightGreen;
scoreBoardTable.CellFormatting += OnScoreBoardCellFormatting;
}
private void UpdateScoreBoard()
{
scoreBoardTable.ColumnCount = 3 + games.Count;
for (int c = 0; c < scoreBoardTable.ColumnCount; c++)
{
var col = scoreBoardTable.Columns[c];
if (c == 0)
{
col.Name = "Rank";
col.HeaderText = "";
col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
col.Width = 48;
}
else if (c == 1)
{
col.Name = "Player";
col.HeaderText = "Player";
col.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
}
else if (c == scoreBoardTable.ColumnCount - 1)
{
col.Name = "Totals";
col.HeaderText = "Totals";
col.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
//col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
else
{
var game = games[c - 2];
col.Name = "Game_" + game.ID;
col.HeaderText = game.Name;
col.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
//col.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
}
}
scoreBoardTable.RowCount = players.Count;
scoreBoardTable.AutoResizeColumnHeadersHeight();
scoreBoardTable.Invalidate();
}
private void OnScoreBoardCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
var player = players[e.RowIndex];
int col = e.ColumnIndex;
if (col == 0)
e.Value = "";
else if (col == 1)
e.Value = player.Name;
else if (col == scoreBoardTable.ColumnCount - 1)
e.Value = player.Total.ToString();
else
{
var game = games[col - 2];
e.Value = GetScore(player, game).ToString();
}
e.FormattingApplied = true;
}
}
}

Well, the CellPaint event was the culprit. I was able to achieve what I wanted by negating the CellPaint event, and instead manipulating the controls in the panel so as to have the right background colors as well as size so they fill the grid.
Thank you for all your comments - they were very helpful. As per HighCore's comment, I will now be looking into WPF and I might be able to get something even slicker.

Related

Connect 4 regardless of which cells is clicked on a grid find the bottom cell and change its image

All grid cells are white images which are initially set to 0 and when clicked are either set to 1 or 2 depending on the color.
I cant figure out how to make it so regardless of which white image the user clicks it will go to the bottom of that column, find the last cell with the value of 0 and fill that cell with the colored tile.
string[] imagePaths = { "empty.png", "Yellow.png", "Red.png" };
const int NumberOfCells = 36;
const int WidthOfBoard = 6;
//defualt player
string playersTurn = "Red";
int[] boardValues = new int[NumberOfCells];
ImageButton[] buttons = new ImageButton[NumberOfCells];
public MainPage()
{
InitializeComponent();
for (int i = 0; i < NumberOfCells; i++)
{
buttons[i] = (ImageButton)board.FindByName("cell" + i);
}
ResetGame();
Rules();
}
//put image of blue or red tile on grid and update turn
private async void Cell_Clicked(object sender, EventArgs e)
{
ImageButton button = (ImageButton)sender;
int y = (int)button.GetValue(Grid.ColumnProperty);
int x = (int)button.GetValue(Grid.RowProperty);
int index = (y * WidthOfBoard) + x;
if (boardValues[index] == 0)
{
{
button.TranslationY = -400;
buttons[index].Source = playersTurn + ".png";
if (playersTurn == "Yellow")
{
boardValues[index] = 1;
CheckForWinner();
playersTurn = "Red";
}
else
{
boardValues[index] = 2;
CheckForWinner();
playersTurn = "Yellow";
}
turnLabel.Text = playersTurn + "'s Turn";
await button.TranslateTo(0, 0, 250);
}
}
}
How the board looks

Delete rectangle annotations from Chart

I have a list of signals in a listview. When the user checks one, the values of the signals are being plotted on the chart. Moreover there is a vertical annotation which the user can drag across the graph and see the values for every x value. Each signal has one rectangle annotation that shows the Y value.
My problem is that when the user checks a new signal then the old rectangle annotations do not disappear.
Here is what I mean :
enter image description here
Here is my code so far :
List<RectangleAnnotation> anno = new List<RectangleAnnotation>();
List<Series> checkedItems = new List<Series>();
private void listView1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (listView1.FocusedItem != null)
{
double xFactor = 0.03;
double yFactor = 0.02;
CA = chart1.ChartAreas[0];
if (e.NewValue == CheckState.Checked)
{
anno.Clear();
Series s12 = new Series();
s12 = chart1.Series.Add((listView1.Items[e.Index].Text).ToString());
s12.ChartType = SeriesChartType.Line;
s12.MarkerStyle = MarkerStyle.Circle; // make the points stand out
s12.MarkerSize = 3;
checkedItems.Add(s12);
for (int i = 0; i < chart1.Series.Count - 1; i++)
{
anno.Add(new RectangleAnnotation());
anno[i].AxisX = CA.AxisX;
anno[i].IsSizeAlwaysRelative = false;
anno[i].Width = 20 * xFactor;
anno[i].Height = 8 * yFactor;
// VA.Name = "myRect";
anno[i].LineColor = Color.Black;
anno[i].BackColor = Color.Black;
anno[i].AxisY = CA.AxisY;
anno[i].Y = -anno[i].Height;
// RA[i].X = VA.X - RA[i].Width / 2;
anno[i].Text = "Hello";
anno[i].ForeColor = Color.Black;
anno[i].Font = new System.Drawing.Font("Arial", 8f);
anno[i].Text = String.Format("{0:0.00}", 0);
chart1.Annotations.Add(anno[i]);
}
for (int r = 0; r < num_rows; r++)
{
DataPoint dp = new DataPoint();
dp.SetValueXY(r, values[r, listView1.Items.IndexOf(listView1.Items[e.Index])]);
// chart1.Series[checkedListBox1.Items[e.Index].ToString()].Points.Add(dp);
s12.Points.AddXY(r, values[r, listView1.Items.IndexOf(listView1.Items[e.Index])]);
}
}
}
}
private void chart1_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e)
{
int pt1 = (int)e.NewLocationX;
int i = 0;
foreach (var signal in checkedItems) {
double val = signal.Points[pt1].YValues[0];
foreach (var sim in signal.Points[pt1].YValues)
{
anno[i].Y = sim + 0.5;
}
if (sender == VA) anno[i].X = VA.X - anno[i].Width / 2;
anno[i].Text = String.Format("{0:0.00}", val);
i++;
Console.WriteLine(anno.Count);
}
I have thought of adding
chart1.Annotations.clear();
But it deletes all Annotations including the vertical. I only want to delete the rectangle annotations.

C# find panels adjecent to panel being clicked

I'm trying to make a little game where you turn all panels green.
I do this by getting a 5x5 grid of panels, every panel has a 1/3 chance to be green, otherwise it will start as red.
my problem is that i do not have the slightest clue how to start the main problem.
when i click a panel, the panel above, left ,right and below need to change color aswell.
at the moment i do not know how to identify which panels are next to the one being clicked.
this is my code:
public partial class Form1 : Form
{
Panel[,] PanelArray = new Panel[5,5];
Random R = new Random();
int R1;
public Form1()
{
InitializeComponent();
for (int r = 0; r < 5; r++)
{
for (int c = 0; c < 5; c++)
{
R1 = R.Next(0, 3);
PanelArray[r, c] = new Panel
{
Size = new Size(50, 50),
Location = new Point(PanelContainer.Width / 5 * c, PanelContainer.Height / 5 * r),
BackColor = Color.Red,
BorderStyle = BorderStyle.Fixed3D
};
PanelArray[r, c].Click += new EventHandler(PanelArray_Click);
if (R1 == 1) PanelArray[r, c].BackColor = Color.Green;
PanelContainer.Controls.Add(PanelArray[r, c]);
}
}
}
private void PanelArray_Click(object sender, EventArgs e)
{
Panel P = (Panel)sender;
if (P.BackColor == Color.Red) P.BackColor = Color.Green;
else if (P.BackColor == Color.Green) P.BackColor = Color.Red;
if (CheckWin()) MessageBox.Show("test");
}
private bool CheckWin()
{
//foreach panel green blah blah
return false;
}
}
}`
You can use the Tag property in your Panel objects to store some information.
PanelArray[r, c] = new Panel
{
Size = new Size(50, 50),
Location = new Point(PanelContainer.Width / 5 * c, PanelContainer.Height / 5 * r),
BackColor = Color.Red,
BorderStyle = BorderStyle.Fixed3D,
Tag = (Row: r, Column: c)
};
In your PanelArray_Click method, you can get the indexes:
var indexes = ((int Row, int Column))P.Tag;
var row = indexes.Row;
var column = indexes.Column;
// Todo: your logic here
In the Tag property, you can store any object, so you can create some class to store data, if you need.
Other solution is two for loops, to get the indexes, like:
private (int Row, int Column) GetIndexes(Panel panel)
{
for (int x = 0; x < PanelArray.GetLength(0); x++)
{
for (int y = 0; y < PanelArray.GetLength(1); y++)
{
if (PanelArray[x, y] == panel)
{
return (x, y);
}
}
}
throw new Exception("Not found.");
}
And then you can use in your PanelArray_Click method:
var indexes = this.GetIndexes(P);
var row = indexes.Row;
var column = indexes.Column;
// Todo: your logic here
Here is easy trick to get row and column. Create a class that inherits the Panel and adds a row and column. See code below
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
MyPanel[,] PanelArray = new MyPanel[5, 5];
Random R = new Random();
int R1;
public Form1()
{
InitializeComponent();
for (int r = 0; r < 5; r++)
{
for (int c = 0; c < 5; c++)
{
R1 = R.Next(0, 3);
PanelArray[r, c] = new MyPanel
{
Size = new Size(50, 50),
Location = new Point(PanelContainer.Width / 5 * c, PanelContainer.Height / 5 * r),
BackColor = Color.Red,
BorderStyle = BorderStyle.Fixed3D,
row = r,
col = c
};
PanelArray[r, c].Click += new EventHandler(PanelArray_Click);
if (R1 == 1) PanelArray[r, c].BackColor = Color.Green;
PanelContainer.Controls.Add(PanelArray[r, c]);
}
}
}
private void PanelArray_Click(object sender, EventArgs e)
{
MyPanel P = sender as MyPanel;
int row = P.row;
int col = P.col;
if (P.BackColor == Color.Red) P.BackColor = Color.Green;
else if (P.BackColor == Color.Green) P.BackColor = Color.Red;
if (CheckWin()) MessageBox.Show("test");
}
private bool CheckWin()
{
//foreach panel green blah blah
return false;
}
}
public class MyPanel : Panel
{
public int row { get; set; }
public int col { get; set; }
}
}

Print all data in the DataGrid in WPF

I am working on WPF application. I have data in the DataGrid which I have to print all the data present in it. I tried like this...
publicMainWindow()
{
InitializeComponent();
DataTabledt = newDataTable();
dt.Columns.Add("S.No");
dt.Columns.Add("Name");
dt.Columns.Add("Father's Name");
dt.Columns.Add("D-O-B");
dt.Columns.Add("Qualification");
dt.Columns.Add("Gender");
dt.Columns.Add("SSC %");
dt.Columns.Add("+2 %");
dt.Columns.Add("Graduation %");
dt.Columns.Add("Work Experience");
dt.Columns.Add("Company");
object[] rowValues = {"01","Gopi","Ravi","31","Degree","M", "88","85", "80","2 Years","Blah Blah"};
dt.Rows.Add(rowValues);
dt.AcceptChanges();
myGrid.DataContext = dt.DefaultView;
}
privatevoidPrint_Click(object sender, RoutedEventArgs e)
{
PrintDialogprintDlg = newPrintDialog();
if ((bool)printDlg.ShowDialog().GetValueOrDefault())
{
Sizepagesize = newSize(printDlg.PrintableAreaWidth,printDlg.PrintableAreaHeight);
myGrid.Measure(pagesize);
myGrid.Arrange(newRect(5, 5, pagesize.Width, pagesize.Height));
printDlg.PrintVisual(myGrid, "Personal Information");
}
}
when I click on print button it is printing only the data which we can see as below
But in my case it is not printing work experience and company columns. How can I Print all the fields. Please help me out
EDIT: I think FlowDocument is used, but suppose I have 50 rows I cannot use FlowDocument. How can I Print in this case.
I have done code recently. It is tested code.It will print every datagrid with all records.It is easy and simple code.You would add a class. If you want to decorate a datagrid then go to PrintDG class then decorate it according to your own requirement.
Follow these steps.
Step1: Add these references on top.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
public class PrintDG
{
public void printDG(DataGrid dataGrid, string title)
{
PrintDialog printDialog = new PrintDialog();
if (printDialog.ShowDialog() == true)
{
FlowDocument fd = new FlowDocument();
Paragraph p = new Paragraph(new Run(title));
p.FontStyle = dataGrid.FontStyle;
p.FontFamily = dataGrid.FontFamily;
p.FontSize = 18;
fd.Blocks.Add(p);
Table table = new Table();
TableRowGroup tableRowGroup = new TableRowGroup();
TableRow r = new TableRow();
fd.PageWidth = printDialog.PrintableAreaWidth;
fd.PageHeight = printDialog.PrintableAreaHeight;
fd.BringIntoView();
fd.TextAlignment = TextAlignment.Center;
fd.ColumnWidth = 500;
table.CellSpacing = 0;
var headerList = dataGrid.Columns.Select(e => e.Header.ToString()).ToList();
List<dynamic> bindList = new List<dynamic>();
for (int j = 0; j < headerList.Count; j++)
{
r.Cells.Add(new TableCell(new Paragraph(new Run(headerList[j]))));
r.Cells[j].ColumnSpan = 4;
r.Cells[j].Padding = new Thickness(4);
r.Cells[j].BorderBrush = Brushes.Black;
r.Cells[j].FontWeight = FontWeights.Bold;
r.Cells[j].Background = Brushes.DarkGray;
r.Cells[j].Foreground = Brushes.White;
r.Cells[j].BorderThickness = new Thickness(1, 1, 1, 1);
var binding = (dataGrid.Columns[j] as DataGridBoundColumn).Binding as Binding;
bindList.Add(binding.Path.Path);
}
tableRowGroup.Rows.Add(r);
table.RowGroups.Add(tableRowGroup);
for (int i = 0; i < dataGrid.Items.Count; i++)
{
dynamic row;
if (dataGrid.ItemsSource.ToString().ToLower() == "system.data.linqdataview")
{ row = (DataRowView)dataGrid.Items.GetItemAt(i); }
else
{
row = (BalanceClient)dataGrid.Items.GetItemAt(i);
}
table.BorderBrush = Brushes.Gray;
table.BorderThickness = new Thickness(1, 1, 0, 0);
table.FontStyle = dataGrid.FontStyle;
table.FontFamily = dataGrid.FontFamily;
table.FontSize = 13;
tableRowGroup = new TableRowGroup();
r = new TableRow();
for (int j = 0; j < row.Row.ItemArray.Count(); j++)
{
if (dataGrid.ItemsSource.ToString().ToLower() == "system.data.linqdataview")
{
r.Cells.Add(new TableCell(new Paragraph(new Run(row.Row.ItemArray[j].ToString()))));
}
else
{
r.Cells.Add(new TableCell(new Paragraph(new Run(row.GetType().GetProperty(bindList[j]).GetValue(row, null)))));
}
r.Cells[j].ColumnSpan = 4;
r.Cells[j].Padding = new Thickness(4);
r.Cells[j].BorderBrush = Brushes.DarkGray;
r.Cells[j].BorderThickness = new Thickness(0, 0, 1, 1);
}
tableRowGroup.Rows.Add(r);
table.RowGroups.Add(tableRowGroup);
}
fd.Blocks.Add(table);
printDialog.PrintDocument(((IDocumentPaginatorSource)fd).DocumentPaginator, "");
}
}
}
Step2: Then go to print button click event and create object of PrintDG class then call printDG pass to It two parameters datagridname and title.
Like :
private void print_button_Click(object sender, RoutedEventArgs e)
{
PrintDG print = new PrintDG();
print.printDG(datagridName, "Title");
}
If any error occurs during execution tell me and I will solve It.This is running code only, you need copy and paste.
Edited:
I declared row as dynamic. The dynamic keyword decides at run time which type to instantiate, either DataTable or another.
I work with This :
// Author : Kadi Okba
public class WpfPrinting
{
public const double cm = 37;
public double Margin = 0.5 * cm;
public double PageWidth = 21 * cm;
public double PageHeight = 29 * cm;
public double RowHeight = 0.7 * cm;
public bool PageNumberVisibility = true;
public bool DateVisibility = true;
public double FontSize = 14;
public double HeaderFontSize = 14;
public bool IsBold = false;
public void PrintDataGrid(FrameworkElement header, DataGrid grid, FrameworkElement footer, PrintDialog printDialog)
{
if (header == null) { header = new FrameworkElement(); header.Width = 1; header.Height = 1; }
if (footer == null) { footer = new FrameworkElement(); footer.Width = 1; footer.Height = 1; }
if (grid == null) return;
Size pageSize = new Size(PageWidth, PageHeight);
FixedDocument fixedDoc = new FixedDocument();
fixedDoc.DocumentPaginator.PageSize = pageSize;
double GridActualWidth = grid.ActualWidth == 0 ? grid.Width : grid.ActualWidth;
double PageWidthWithMargin = pageSize.Width - Margin * 2;
double PageHeightWithMargin = pageSize.Height - Margin * 2;
// scale the header
double headerScale = (header?.Width ?? 0) / PageWidthWithMargin;
double headerWidth = PageWidthWithMargin;
double headerHeight = (header?.Height ?? 0) * headerScale;
header.Height = headerHeight;
header.Width = headerWidth;
// scale the footer
double footerScale = (footer?.Width ?? 0) / PageWidthWithMargin;
double footerWidth = PageWidthWithMargin;
double footerHeight = (footer?.Height ?? 0) * footerScale;
footer.Height = footerHeight;
footer.Width = footerWidth;
int pageNumber = 1;
string Now = DateTime.Now.ToShortDateString();
//add the header
FixedPage fixedPage = new FixedPage();
fixedPage.Background = Brushes.White;
fixedPage.Width = pageSize.Width;
fixedPage.Height = pageSize.Height;
FixedPage.SetTop(header, Margin);
FixedPage.SetLeft(header, Margin);
fixedPage.Children.Add(header);
// its like cursor for current page Height to start add grid rows
double CurrentPageHeight = headerHeight + 1 * cm;
int lastRowIndex = 0;
bool IsFooterAdded = false;
for (;;)
{
int AvaliableRowNumber;
var SpaceNeededForRestRows = (CurrentPageHeight + (grid.Items.Count - lastRowIndex) * RowHeight);
//To avoid printing the footer in a separate page
if (SpaceNeededForRestRows > (pageSize.Height - footerHeight - Margin) && (SpaceNeededForRestRows < (pageSize.Height - Margin)))
AvaliableRowNumber = (int)((pageSize.Height - CurrentPageHeight - Margin - footerHeight) / RowHeight);
// calc the Avaliable Row acording to CurrentPageHeight
else AvaliableRowNumber = (int)((pageSize.Height - CurrentPageHeight - Margin) / RowHeight);
// create new page except first page cause we created it prev
if (pageNumber > 1)
{
fixedPage = new FixedPage();
fixedPage.Background = Brushes.White;
fixedPage.Width = pageSize.Width;
fixedPage.Height = pageSize.Height;
}
// create new data grid with columns width and binding
DataGrid gridToAdd;
gridToAdd = GetDataGrid(grid, GridActualWidth, PageWidthWithMargin);
FixedPage.SetTop(gridToAdd, CurrentPageHeight); // top margin
FixedPage.SetLeft(gridToAdd, Margin); // left margin
// add the avaliable rows to the cuurent grid
for (int i = lastRowIndex; i < grid.Items.Count && i < AvaliableRowNumber + lastRowIndex; i++)
{
gridToAdd.Items.Add(grid.Items[i]);
}
lastRowIndex += gridToAdd.Items.Count + 1;
// add date
TextBlock dateText = new TextBlock();
if (DateVisibility) dateText.Visibility = Visibility.Visible;
else dateText.Visibility = Visibility.Hidden;
dateText.Text = Now;
// add page number
TextBlock PageNumberText = new TextBlock();
if (PageNumberVisibility) PageNumberText.Visibility = Visibility.Visible;
else PageNumberText.Visibility = Visibility.Hidden;
PageNumberText.Text = "Page : " + pageNumber;
FixedPage.SetTop(dateText, PageHeightWithMargin);
FixedPage.SetLeft(dateText, Margin);
FixedPage.SetTop(PageNumberText, PageHeightWithMargin);
FixedPage.SetLeft(PageNumberText, PageWidthWithMargin - PageNumberText.Text.Length * 10);
fixedPage.Children.Add(gridToAdd);
fixedPage.Children.Add(dateText);
fixedPage.Children.Add(PageNumberText);
// calc Current Page Height to know the rest Height of this page
CurrentPageHeight += gridToAdd.Items.Count * RowHeight;
// all grid rows added
if (lastRowIndex >= grid.Items.Count)
{
// if footer have space it will be added to the same page
if (footerHeight < (PageHeightWithMargin - CurrentPageHeight))
{
FixedPage.SetTop(footer, CurrentPageHeight + Margin);
FixedPage.SetLeft(footer, Margin);
fixedPage.Children.Add(footer);
IsFooterAdded = true;
}
}
fixedPage.Measure(pageSize);
fixedPage.Arrange(new Rect(new Point(), pageSize));
fixedPage.UpdateLayout();
PageContent pageContent = new PageContent();
((IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
pageNumber++;
// go to start position : New page Top
CurrentPageHeight = Margin;
// this mean that lastRowIndex >= grid.Items.Count and the footer dont have enough space
if (lastRowIndex >= grid.Items.Count && !IsFooterAdded)
{
FixedPage ffixedPage = new FixedPage();
ffixedPage.Background = Brushes.White;
ffixedPage.Width = pageSize.Width;
ffixedPage.Height = pageSize.Height;
FixedPage.SetTop(footer, Margin);
FixedPage.SetLeft(footer, Margin);
TextBlock fdateText = new TextBlock();
if (DateVisibility) fdateText.Visibility = Visibility.Visible;
else fdateText.Visibility = Visibility.Hidden;
dateText.Text = Now;
TextBlock fPageNumberText = new TextBlock();
if (PageNumberVisibility) fPageNumberText.Visibility = Visibility.Visible;
else fPageNumberText.Visibility = Visibility.Hidden;
fPageNumberText.Text = "Page : " + pageNumber;
FixedPage.SetTop(fdateText, PageHeightWithMargin);
FixedPage.SetLeft(fdateText, Margin);
FixedPage.SetTop(fPageNumberText, PageHeightWithMargin);
FixedPage.SetLeft(fPageNumberText, PageWidthWithMargin - PageNumberText.ActualWidth);
ffixedPage.Children.Add(footer);
ffixedPage.Children.Add(fdateText);
ffixedPage.Children.Add(fPageNumberText);
ffixedPage.Measure(pageSize);
ffixedPage.Arrange(new Rect(new Point(), pageSize));
ffixedPage.UpdateLayout();
PageContent fpageContent = new PageContent();
((IAddChild)fpageContent).AddChild(ffixedPage);
fixedDoc.Pages.Add(fpageContent);
IsFooterAdded = true;
}
if (IsFooterAdded)
{
break;
}
}
PrintFixedDocument(fixedDoc, printDialog);
}
private DataGrid GetDataGrid(DataGrid grid, double GridActualWidth, double PageWidthWithMargin)
{
DataGrid printed = new DataGrid();
// styling the grid
Style rowStyle = new Style(typeof(DataGridRow));
rowStyle.Setters.Add(new Setter(Control.BackgroundProperty, Brushes.White));
rowStyle.Setters.Add(new Setter(Control.FontSizeProperty, FontSize));
if (IsBold) rowStyle.Setters.Add(new Setter(Control.FontWeightProperty, FontWeights.Bold));
rowStyle.Setters.Add(new Setter(Control.HeightProperty, RowHeight));
Style columnStyle = new Style(typeof(DataGridColumnHeader));
columnStyle.Setters.Add(new Setter(Control.FontSizeProperty, HeaderFontSize));
columnStyle.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Center));
columnStyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0, 0.5, 0, 1.5)));
columnStyle.Setters.Add(new Setter(Control.BackgroundProperty, Brushes.White));
columnStyle.Setters.Add(new Setter(Control.BorderBrushProperty, Brushes.Black));
columnStyle.Setters.Add(new Setter(Control.FontWeightProperty, FontWeights.SemiBold));
printed.RowStyle = rowStyle;
printed.VerticalGridLinesBrush = Brushes.Black;
printed.HorizontalGridLinesBrush = Brushes.Black;
printed.FontFamily = new FontFamily("Arial");
printed.RowBackground = Brushes.White;
printed.Background = Brushes.White;
printed.Foreground = Brushes.Black;
// get the columns of grid
foreach (var column in grid.Columns)
{
if (column.Visibility != Visibility.Visible) continue;
DataGridTextColumn textColumn = new DataGridTextColumn();
textColumn.HeaderStyle = columnStyle;
textColumn.Header = column.Header;
textColumn.Width = column.ActualWidth / GridActualWidth * PageWidthWithMargin;
textColumn.Binding = ((DataGridTextColumn)column).Binding;
printed.Columns.Add(textColumn);
}
printed.BorderBrush = Brushes.Black;
return printed;
}
public void PrintFixedDocument(FixedDocument fixedDoc, PrintDialog printDialog)
{
XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(printDialog.PrintQueue);
writer.Write(fixedDoc, printDialog.PrintTicket);
}
}

button event with validation and actions

I need help with the Check button. After a user adds all the 42 numbers in the textbox and enter a number from 0-9 in the "Enter number" area and clicks on the start button, next what he should do is run through the array of labels with the red label or lblCovece and he should collect the same values like the number enters before. And after he clicks on the Check button, the programme should first validate if the value that is selected with the red label is the same as the number entered. If is valid the label should turn green and than the result should appear in the label lblResultE(the result for example should be like this: if the number entered is 2, the result it is 2+2+2...)and if is not valid in the lblResultE we take out 10 points. That's what i did by now with some help.:) thank you.
namespace Seminarska
{
public partial class Form1 : Form
{
private Label l,l2,lblCovece,l4,lblResultE;
private Button bUp, bRight, bLeft, bDown, bCheck,bStart, bReset;
private TextBox txtVnes, txtGoal;
private Label[] pole;
public Form1()
{
InitializeComponent();
l2 = new Label();
l2.Text = " Enter one number";
l2.Location = new Point(230, 200);
l2.AutoSize = true;
l4 = new Label();
l4.Text = "Score";
l4.Location = new Point(240, 260);
l4.AutoSize = true;
lblResultE = new Label();
lblResultE.Location = new Point(350, 260);
lblResultE.AutoSize = true;
bLeft = new Button();
bLeft.Location = new Point(0, 250);
bLeft.Width=75;
bLeft.Height = 25;
bLeft.Text = "LEFT";
bCheck = new Button();
bCheck.Location = new Point(75, 250);
bCheck.Width = 75;
bCheck.Height = 25;
bCheck.Text = "Check";
bRight = new Button();
bRight.Location = new Point(150, 250);
bRight.Width = 75;
bRight.Height = 25;
bRight.Text = "RIGHT";
bUp = new Button();
bUp.Location = new Point(75, 220);
bUp.Width = 75;
bUp.Height = 25;
bUp.Text = "UP";
bDown = new Button();
bDown.Location = new Point(75, 280);
bDown.Width = 75;
bDown.Height = 25;
bDown.Text = "DOWN";
bStart = new Button();
bStart.Location = new Point(240, 165);
bStart.Width = 75;
bStart.Height = 25;
bStart.Text = "START";
bReset = new Button();
bReset.Location = new Point(320, 165);
bReset.Width = 75;
bReset.Height = 25;
bReset.Text = "RESET";
txtVnes = new TextBox();
txtVnes.Location = new Point(240, 10);
txtVnes.Width = 160;
txtVnes.Height = 130;
txtVnes.Multiline = true;
txtGoal = new TextBox();
txtGoal.Width = 75;
txtGoal.Height = 25;
txtGoal.Location = new Point(330, 200);
lblCovece = new Label();
lblCovece.Location = new Point(160,165);
lblCovece.Width = 20;
lblCovece.Height = 20;
lblCovece.TextAlign = ContentAlignment.MiddleCenter;
lblCovece.Text = "O";
lblCovece.BackColor = Color.FromArgb(255, 0, 0);
int a = 0;
pole = new Label[42];
this.Controls.Add(lblCovece);
for (int i = 1; i <= 6; i++)
{
for (int j = 1; j <= 7; j++)
{
l = new Label();
l.Name = "label" + i.ToString() + j.ToString();
l.Text = "Z";
l.Width = 20;
l.Height = 20;
l.TextAlign = ContentAlignment.MiddleCenter;
l.Parent = this;
l.BackColor = Color.FromArgb(100, 149, 237);
l.Location = new Point(10 + (j - 1) * 25, 15 + (i - 1) * 25);
pole[a] = l;
this.Controls.Add(l);
a++;
}
}
this.Width = 460;
this.Height = 380;
this.Controls.Add(l2);
this.Controls.Add(l4);
this.Controls.Add(lblResultE);
this.Controls.Add(lblTimeE);
this.Controls.Add(bStart);
this.Controls.Add(bReset);
this.Controls.Add(txtGoal);
this.Controls.Add(txtVnes);
this.Controls.Add(bUp);
this.Controls.Add(bLeft);
this.Controls.Add(bRight);
this.Controls.Add(bDown);
this.Controls.Add(bCheck);
bStart.Click+=new EventHandler(bStart_Click);
bUp.Click+=new EventHandler(bUp_Click);
bDown.Click+=new EventHandler(bDown_Click);
bLeft.Click+=new EventHandler(bLeft_Click);
bRight.Click+=new EventHandler(bRight_Click);
bCheck.Click+=new EventHandler(bZemaj_Click);
bReset.Click+=new EventHandler(bReset_Click);
}
private void bStart_Click(object sender, EventArgs e)
{
string Str = txtGoal.Text.Trim();
int Num;
bool isNum = int.TryParse(Str, out Num);
if (isNum && Str.Length == 1)
{
string[] ts = txtVnes.Text.Split(
new string[] { "\r\n" },
StringSplitOptions.RemoveEmptyEntries);
int row = 0;
for (int i = 0; i < ts.Length && row < 6; i++)
{
if (LineIsValid(ts[i]))
{
for (int col = 0; col < 7; col++)
{
pole[row * 7 + col].Text = ts[i][2 * col].ToString();
}
row++;
}
}
for (; row < 6; row++)
{
for (int col = 0; col < 7; col++)
{
pole[row * 7 + col].Text = "Z";
}
}
}
else
{
MessageBox.Show("Invalid Input");
}
}
private static Regex regex = new Regex(#"^(\s)*(\d ){6}\d(\s)*$");
private static bool LineIsValid(string line)
{
return regex.IsMatch(line);
}
private void bReset_Click(object sender, EventArgs e)
{
txtVnes.Clear();
string[] ts = txtVnes.Text.Split(new string[] { "\r\n" },
StringSplitOptions.RemoveEmptyEntries);
int row = 0;
for (int i = 0; i < ts.Length && row < 6; i++)
{
for (int col = 0; col < 7; col++)
{
pole[row * 7 + col].Text = "Z";
pole[row * 7 + col].BackColor=Color.FromArgb(100, 149, 237);
}
row++;
}
for (; row < 6; row++)
{
for (int col = 0; col < 7; col++)
{
pole[row * 7 + col].Text = "Z";
pole[row * 7 + col].BackColor = Color.FromArgb(100, 149, 237);
}
}
txtGoal.Clear();
lblCovece.Location=new Point(160,165);
}
private void bUp_Click(object sender, EventArgs e)
{
lblCovece.Location = new Point(lblCovece.Location.X, lblCovece.Location.Y -
25);
}
private void bDown_Click(object sender, EventArgs e)
{
lblCovece.Location = new Point(lblCovece.Location.X, lblCovece.Location.Y +
25);
}
private void bLeft_Click(object sender, EventArgs e)
{
lblCovece.Location = new Point(lblCovece.Location.X - 25,
lblCovece.Location.Y);
}
private void bRight_Click(object sender, EventArgs e)
{
lblCovece.Location = new Point(lblCovece.Location.X + 25,
lblCovece.Location.Y);
}
private void bCheck_Click(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
What makes your programm complicated and difficult to understand, is that you mix game logic with display logic.
I suggest you to redesign your game. It could look something like this:
public enum State
{
Empty, // Displays "Z"
Neutral, // Blue
Good, // Green
Bad // Red
}
public class Square
{
public int Number { get; set; }
public State State { get; set; }
}
public class Game
{
public const int Width = 7, Height = 6;
public Game()
{
Board = new Square[Width, Height];
}
public event EventHandler GameChanged;
public Square[,] Board { get; private set; }
public int CurrentX { get; private set; }
public int CurrentY { get; private set; }
public void Reset()
{
for (int x = 0; x < Width; x++) {
for (int y = 0; y < Height; y++) {
Board[x, y].State = State.Empty; // Always displayed in blue as "Z"
}
}
OnGameChanged();
}
public void MoveLeft()
{
if (CurrentX > 0) {
CurrentX--;
OnGameChanged();
}
}
public void MoveRight()
{
if (CurrentX < Width - 1) {
CurrentX++;
OnGameChanged();
}
}
// and so on
private void OnGameChanged()
{
EventHandler eh = GameChanged;
if (eh != null) {
eh(this, EventArgs.Empty);
}
}
}
In the form I would define pole to be a matrix as well (like the board). I show only a few relevant parts of the form code, to give you an idea of what I mean:
public class Form1 : Form
{
private Game game;
private Label[,] pole;
public Form1()
{
game = new Game();
game.GameChanged += new EventHandler(Game_GameChanged);
pole = new Label[Game.Width, Game.Height];
// Intialize pole.
// ...
}
void Game_GameChanged(object sender, EventArgs e)
{
for (int x = 0; x < Game.Width; x++) {
for (int y = 0; y < Game.Height; y++) {
Square square = game.Board[x, y];
Label label = pole[x,y];
switch (square.State) {
case State.Empty:
label.BackColor = Color.Blue;
label.Text = "Z";
break;
case State.Neutral:
label.BackColor = Color.Blue;
label.Text = square.Number.ToString();
break;
case State.Good:
label.BackColor = Color.Green;
label.Text = square.Number.ToString();
break;
case State.Bad:
label.BackColor = Color.Red;
label.Text = square.Number.ToString();
break;
default:
break;
}
}
}
// Place lblCovece according to game.CurrentX and game.CurrentY
// ...
}
private void bReset_Click(object sender, EventArgs e)
{
game.Reset();
}
private void bLeft_Click(object sender, EventArgs e)
{
game.MoveLeft();
}
private void bRight_Click(object sender, EventArgs e)
{
game.MoveRight();
}
}
Note how the Game class tells the form when changes happen through the event GameChanged. The form then updates the game display. In the game class, you can now concentrate on the game logic and do not have to deal with buttons and labels. You can also work with logical coordinates in the range [0..6] and [0..5] of the game board. This is easier than working with pixels. You delegate all the pixel calculations to the form.
My example is not complete, but when you try to implement it, you will see that it will be much easier to think about how the logic of the game should work.
Add an int score;
private void bCheck_Click(object sender, EventArgs e)
{
bool found = false;
foreach (Label l in pole)
{
if (l.Location == lblCovece.Location && l.Text == txtGoal.Text)
{
l.BackColor = Color.Green;
score += int.Parse(l.Text);
lblResultE.Text = score.ToString();
found = true;
}
}
if (!found)
{
score -= 10;
lblResultE.Text = score.ToString();
}
}

Categories

Resources