I'm trying to understand how to speed up some graphical controls updates. When there are large numbers of controls on a screen, the updates happen slow as shown in the example below. How can I speed this up so that it updates all the controls at the same time with a 50ms update rate specified in the timer?
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Timer = System.Windows.Forms.Timer;
namespace FormTestApplication
{
public partial class Form1 : Form
{
private List<Label> labels = new List<Label>();
Timer t = new Timer();
private Boolean flag = false;
public Form1()
{
InitializeComponent();
for (int j = 0; j < 20; j++)
{
for (int i = 0; i < 20; i++)
{
Label l = new Label();
l.Top = j * 30;
l.Left = i * 25 + 20;
l.BackColor = Color.Red;
l.Width = 20;
labels.Add(l);
}
}
foreach (var label in labels)
{
this.Controls.Add(label);
}
t.Interval = 50;
t.Tick += t_Tick;
t.Start();
}
void t_Tick(object sender, EventArgs e)
{
foreach (var label in labels)
{
if (label.BackColor == Color.Red)
{
label.BackColor = Color.Green;
}
else
{
label.BackColor = Color.Red;
}
}
}
}
}
Related
I am making a Memory game in WPF and C#. It is going good till now. When I click (turn) 2 cards, I want my code to register that and when the images don't match then I want the back.png image to come back.
Now my code counts how many times there has been clicked but I don't know how to make the cards "turn" again and to make them go away when 2 images match. I have 16 images, 1 and 9 are pairs, 2 and 10 are pairs, and so on.
My plan was to make a method that is called resetCards().
This is my MainWindow.cs:
public partial class MainWindow : Window
{
private MemoryGrid grid;
public MainWindow()
{
InitializeComponent();
}
private void start_Click(object sender, RoutedEventArgs e)
{
grid = new MemoryGrid(GameGrid, 4, 4);
start.Visibility = Visibility.Collapsed;
}
This is my MemoryGrid.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace SpellenScherm
{
public class MemoryGrid
{
private Grid grid;
private int rows, cols;
public MemoryGrid(Grid grid, int rows, int cols)
{
this.grid = grid;
this.rows = rows;
this.cols = cols;
InitializeGrid();
AddImages();
}
private void InitializeGrid()
{
for (int i = 0; i < rows; i++)
{
grid.RowDefinitions.Add(new RowDefinition());
}
for (int i = 0; i < cols; i++)
{
grid.ColumnDefinitions.Add(new ColumnDefinition());
}
}
private void AddImages()
{
List<ImageSource> images = GetImagesList();
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
Image back = new Image();
back.Source = new BitmapImage(new Uri("/images/back.png", UriKind.Relative));
back.MouseDown += new System.Windows.Input.MouseButtonEventHandler(CardClick);
back.Tag = images.First();
images.RemoveAt(0);
Grid.SetColumn(back, col);
Grid.SetRow(back, row);
grid.Children.Add(back);
}
}
}
static int numberOfClicks = 0;
private void resetCards()
{
}
private void CardClick(object sender, MouseButtonEventArgs e)
{
if (numberOfClicks < 2)
{
Image card = (Image)sender;
ImageSource front = (ImageSource)card.Tag;
card.Source = front;
numberOfClicks++;
}
if (numberOfClicks == 2)
{
resetCards();
numberOfClicks = numberOfClicks -2;
}
}
public List<ImageSource> GetImagesList()
{
List<ImageSource> images = new List<ImageSource>();
List<string> random = new List<string>();
for (int i = 0; i < 16; i++)
{
int imageNR = 0;
Random rnd = new Random();
imageNR = rnd.Next(1, 17);
if (random.Contains(Convert.ToString(imageNR)))
{
i--;
}
else
{
random.Add(Convert.ToString(imageNR));
ImageSource source = new BitmapImage(new Uri("images/" + imageNR + ".png", UriKind.Relative));
images.Add(source);
}
}
return images;
}
}
}
You can try this approach - keep two fields in your MemoryGrid class one for each of the images which show their front faces. (Let's call them Image1 and Image2). Then you can keep a track of which cards are flipped in the whole grid and pass them as arguments to your resetCards method as follows:
private void CardClick(object sender, MouseButtonEventArgs e)
{
if (numberOfClicks < 2)
{
Image card = (Image)sender;
ImageSource front = (ImageSource)card.Tag;
card.Source = front;
if(this.Image1 == null){
Image1 = card;
}
else if(this.Image2 == null){
Image2 = card;
}
numberOfClicks++;
}
if (numberOfClicks == 2)
{
resetCards(Image1, Image2);
numberOfClicks = numberOfClicks -2;
}
}
I have created WinForm App in which user can set how many textboxes he want (Range 1-99)
I am using this code to create Textboxes during runtime
for (int i = 0; i < Calculation.Num; i++)
{
TextBox txtRun = new TextBox();
txtRun.Name = "txtBox" + i;
txtRun.Location = new System.Drawing.Point(35, 50 + (20 * i) * 2);
txtRun.Size = new System.Drawing.Size(75, 25);
this.Controls.Add(txtRun);
}
Suppose user create 2 textboxes and then enter data in each textbox and click calculate button
Now i want to get the textboxes data and divide it by 100
See The Picture I want txtbox1 and txtbox2 data
EDIT 3:
This is the Whole Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace GPA_Calculatior__New_
{
public partial class Form1 : Form
{
int j = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Label + Marks Obtained Textbox
for (int i = 0; i < Calculation.Num; i++)
{
Label lblCount = new Label();
lblCount.Name = "lblCount" + i;
lblCount.Location = new System.Drawing.Point(5, 55 + (20 * i) * 2);
lblCount.Size = new System.Drawing.Size(20, 30);
lblCount.Text = (i + 1).ToString();
this.Controls.Add(lblCount);
TextBox txtRun = new TextBox();
txtRun.Name = "txtBox" + i;
txtRun.Location = new System.Drawing.Point(35, 50 + (20 * i) * 2);
txtRun.Size = new System.Drawing.Size(75, 25);
this.Controls.Add(txtRun);
}
//Creating Textbox which is for total marks
for (j = 0; j < Calculation.Num; j++)
{
TextBox txtRun = new TextBox();
txtRun.Name = "TotaltxtBox" + j;
txtRun.Location = new System.Drawing.Point(160, 50 + (20 * j) * 2);
txtRun.Size = new System.Drawing.Size(50, 25);
txtRun.Text = "100";
txtRun.Enabled = false;
this.Controls.Add(txtRun);
}
// Creating 2 Buttons (Calculate and Back)
for (int k = 0; k < 2; k++)
{
Button Btn = new Button();
Btn.Name = "btn" + k;
Btn.Location = new System.Drawing.Point(20 + (k *110), 60 + (20 * j) * 2);
Btn.Size = new System.Drawing.Size(90, 30);
if (k == 0)
Btn.Text = "Back";
else
Btn.Text = "Calculate";
Btn.Click += button_Click;
this.Controls.Add(Btn);
}
//Just for Giving free space in last
Label lbl = new Label();
lbl.Name = "lbl" + j;
lbl.Location = new System.Drawing.Point(30, 90 + (20 * j) * 2);
lbl.Size = new System.Drawing.Size(90, 30);
lbl.Text = "";
this.Controls.Add(lbl);
//**********************************************
}
//Caculate and back button function
private void button_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
if (btn.Name.Equals("btn1"))
{
for (int i = 0; i < Calculation.Num; i++)
{
}
}
else
{
GPA_Calculator mainForm = new GPA_Calculator();
mainForm.Show();
this.Hide();
}
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
for (j = 0; j < 10; j++)
{
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
}
}
var sum = this.Controls.OfType<TextBox>()
.Where(t => char.IsDigit(t.Name.Reverse().Take(1).FirstOrDefault())
&& t.Enabled)
.Select(t =>
{
double i;
if (!double.TryParse(t.Text, out i)) { return 0d; }
return i / 100d;
})
.Sum();
This may work, I built a separate class to store the control and its value, then you can work out the values independently from the rest of the form. You need to trigger the calculations though:
private List<InfoTextBox> activeTextBoxes = new List<InfoTextBox>();
public Form1()
{
for (int i = 0; i < Calculation.Num; i++)
{
TextBox txtRun = new TextBox();
txtRun.Name = "txtBox" + i;
txtRun.Location = new System.Drawing.Point(35, 50 + (20 * i) * 2);
txtRun.Size = new System.Drawing.Size(75, 25);
this.Controls.Add(txtRun);
InfoTextBox iBox = new InfoTextBox();
iBox.textbox = txtRun;
activeTextBoxes.Add(iBox);
}
}
public class InfoTextBox
{
private double _textboxValue;
public TextBox textbox { get; set; }
public double TextBoxValue { get { return _textboxValue; } set { _textboxValue = setValue(value); } }
private double setValue(double invalue)
{
return invalue / 100;
}
}
I am creating a number of comboBoxes based on user input. I create the boxes just fine, but when it comes to wanting to check the text within them I am struggling.
I thought of maybe storing them in a IList but that hasn't seemed to work so far. The goal is to change the text of all of them on a button click, but after several attempts I am becoming frustrated.
IList<ComboBox> comboBoxes = new List<ComboBox>();
private void AddComboBox(int i)
{
var comboBoxStudentAttendance = new ComboBox();
comboBoxStudentAttendance.Top = TopMarginDistance(i);
comboBoxStudentAttendance.Items.Add("");
comboBoxStudentAttendance.Items.Add("Present");
comboBoxStudentAttendance.Items.Add("Absent");
comboBoxStudentAttendance.Items.Add("Late");
comboBoxStudentAttendance.Items.Add("Sick");
comboBoxStudentAttendance.Items.Add("Excused");
comboBoxes.Add(comboBoxStudentAttendance);
this.Controls.Add(comboBoxStudentAttendance);
}
I tried the following but with no success.
private void DistributeAttendanceButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < sampleNum; i++)
{
switch (MasterComboBox.Text)
{
case "Present":
comboBoxes.ElementAt(i).Text = "Present";
break;
}
}
}
Try this
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
{
const int TOP_MARGIN = 10;
const int LEFT_MARGIN = 10;
const int WIDTH = 200;
const int HEIGHT = 10;
const int SPACE = 15;
const int NUMBER_OF_BOXES = 10;
public Form1()
{
InitializeComponent();
MasterComboBox.Text = "Present";
for (int i = 0; i < NUMBER_OF_BOXES; i++)
{
AddComboBox(i);
}
}
List<ComboBox> comboBoxes = new List<ComboBox>();
private void AddComboBox(int i)
{
var comboBoxStudentAttendance = new ComboBox();
comboBoxStudentAttendance.Top = TOP_MARGIN + i * (SPACE + HEIGHT);
comboBoxStudentAttendance.Left = LEFT_MARGIN;
comboBoxStudentAttendance.Width = WIDTH;
comboBoxStudentAttendance.Height = HEIGHT;
comboBoxStudentAttendance.Items.Add("");
comboBoxStudentAttendance.Items.Add("Present");
comboBoxStudentAttendance.Items.Add("Absent");
comboBoxStudentAttendance.Items.Add("Late");
comboBoxStudentAttendance.Items.Add("Sick");
comboBoxStudentAttendance.Items.Add("Excused");
comboBoxes.Add(comboBoxStudentAttendance);
this.Controls.Add(comboBoxStudentAttendance);
}
private void DistributeAttendanceButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < comboBoxes.Count; i++)
{
switch (MasterComboBox.Text)
{
case "Present":
comboBoxes[i].Text = "Present";
break;
}
}
}
}
}
I created around 12 picbox and label dynamically im able to retrieve data in the picbox and label from SQL. the picbox image in binary format and the row where imagestore in table also contain image title's in database.
The problem is that I want to add a click_event on picbox. ASAP I click on picbox a textbox1. text which I created must show the title of the image which is store in the SQL.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace library
{
public partial class showingmore : Form
{
private string passvalue;
public string passval
{
get { return passvalue; }
set { passvalue = value; }
}
public showingmore()
{
InitializeComponent();
}
MemoryStream ms;
byte[] photo_aray;
private void showingmore_Load_1(object sender, EventArgs e)
{
OleDbConnection con = new OleDbConnection("Provider=SQLOLEDB;User ID=sa;Password =12345678; Initial Catalog=library; server=raj; TRUSTED_CONNECTION=true;");
OleDbDataAdapter Adap = new OleDbDataAdapter("select * from movie ", con);
textBox1.Text = passvalue;
DataSet ds = new DataSet();
Adap.Fill(ds);
//textBox1.Text = ds.Tables[0].Rows[15][0].ToString(); // the working way to use ds to fill data
//textBox1.Text = ds.Tables[0].Rows[1];
//int icount = ds.Tables[0].Rows.Count;
//textBox1.Text = icount.ToString();
/**** Creating Label's and Picture Box ****/
int n = 12; // total time for running loop.
int j = 14; // y-axis co-ordinate label
int k = 479; // x-axis co-ordinate label
int l = 18; // y-axis co-ordinate label
// Creating label through loop's.
for (int i = 0; i < n; i++)
{
//Create label
Label labels = new Label();
PictureBox picbox = new PictureBox();
labels.Text = ds.Tables[0].Rows[i][0].ToString();
if (i <= 5)
{
//Position label on screen
labels.Location = new Point(j, k);
j = j + 228;
// Label text color
labels.ForeColor = Color.Gainsboro;
}
else
{
k = 782; // x-axis co-ordinate
labels.Location = new Point(l, k);
l = l + 228;
labels.ForeColor = Color.Gainsboro;
}
this.Controls.Add(labels);
}
n = 12; // total time for running loop.
j = 18; // y-axis co-ordinate
k = 246; // x-axis co-ordinate
l = 18; // y-axis co-ordinate
// Creating PictureBox through loop's.
for (int i = 0; i < n; i++)
{
//Create PictureBox
PictureBox picbox = new PictureBox();
picbox.Image = null;
if (ds.Tables[0].Rows[i][14] != System.DBNull.Value)
{
photo_aray = (byte[])ds.Tables[0].Rows[i][14];
MemoryStream ms = new MemoryStream(photo_aray);
picbox.Image = Image.FromStream(ms);
}
if (i <= 5)
{
//Position PictureBox on screen
picbox.Location = new Point(j, k);
picbox.Size = new Size(161, 220);
picbox.BackColor = Color.Gainsboro;
j = j + 228;
}
else
{
k = 543; // y-axis co-ordinate
picbox.Location = new Point(l, k);
picbox.Size = new Size(161, 220);
picbox.BackColor = Color.Gainsboro;
l = l + 228;
}
this.Controls.Add(picbox);
}
}
}
}
To get the click event for your dynamically created PictureBox, you can simple subscribe to the click event when you create it;
private void createPicBoxes()
{
for (int i = 0; i <= 12; i++)
{
PictureBox picBox = new PictureBox();
picBox.Click += picBox_Click;
}
}
static void picBox_Click(object sender, EventArgs e)
{
//do your stuff here which handles generically all of your picture boxes clicks.
}
In short, subscribing to the controls events like such means that whenever that action is performed, in your case a click event, the attached method will fire off.
Put this somewhere in the loop before adding the picbox to the Controls collection:
picbox.MouseClick += picbox_MouseClick;
Then, implement the handler for the click somewhere in your showingmore class:
private void picbox_MouseClick(object sender, MouseEventArgs e)
{
// Your code here.
}
Add event handler to the PictureBox when creating it.
Something like below
PictureBox picbox = new PictureBox();
picbox.Click += new EventHandler(this.picbox_Click);
void picbox_Click(object sender, System.EventArgs e)
{
//your code...
}
I am trying to resize evenly all the columns of a ListView and it works as it should, but the code I made is making the screen flash and blink too much...I wonder what may I fix on the code to make it run smoothly?
Here is the code:
using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
namespace Test_ListViews
{
public partial class Form1 : Form
{
Double[] pesos;
private bool resizing = false;
private bool limpando = false;
public Form1()
{
InitializeComponent();
int i = 0;
float dx = 96;
Graphics g = this.CreateGraphics();
try
{
dx = g.DpiX;
}
finally
{
g.Dispose();
}
pesos = new Double[listView1.Columns.Count]; // usado para o resize das colunas da ListView ser proporcional.
for (i = 0; i < listView1.Columns.Count; i++)
pesos[i] = ((Double)listView1.Columns[i].Width * dx) / (listView1.Width * 96);
_listView1_Resize();
listView1.FullRowSelect = true;
this.listView1.Resize += new System.EventHandler(this.listView1_Resize);
this.listView1.ColumnWidthChanged += new System.Windows.Forms.ColumnWidthChangedEventHandler(this.listView1_ColumnWidthChanged);
}
private void bntFill_Click(object sender, EventArgs e)
{
int i = 0;
for (i = 0; i < 5; i++)
{
ListViewItem item = new ListViewItem("Test 1");
item.SubItems.Add("Test 2");
item.SubItems.Add("Test 3");
item.SubItems.Add("Test 4");
item.SubItems.Add("Test 5");
item.SubItems.Add("Test 6");
item.SubItems.Add("Test 7");
item.SubItems.Add("Test 8");
item.SubItems.Add("Test 9");
listView1.Items.Add(item);
}
SetWindowTheme(listView1.Handle, "Explorer", null);
}
[DllImport("uxtheme.dll")]
public static extern int SetWindowTheme([In] IntPtr hwnd, [In, MarshalAs(UnmanagedType.LPWStr)] string pszSubAppName, [In, MarshalAs(UnmanagedType.LPWStr)] string pszSubIdList);
private void btnDelete_Click(object sender, EventArgs e)
{
ArrayList list = new ArrayList();
foreach(ListViewItem item in listView1.SelectedItems )
{
list.Add(item);
}
foreach (ListViewItem item in list)
{
listView1.Items.Remove(item);
}
}
private void listView1_Resize(object sender, System.EventArgs e)
{
_listView1_Resize();
}
private void _listView1_Resize()
{
if (resizing == false && pesos != null)
{
resizing = true;
Int32 largura = listView1.Width;
int i = 0;
for (i = 0; i < listView1.Columns.Count; i++)
{
listView1.Columns[i].Width = Convert.ToInt32(pesos[i] * largura);
}
if (listView1.Controls.Count > 0)
{
Int32 x = listView1.Items[0].SubItems[listView1.Items[0].SubItems.Count - 1].Bounds.Location.X + 3;//pegando a referencia da ultima coluna.
for (i = 0; i < listView1.Controls.Count; i++)
{
listView1.Controls[i].Location = new System.Drawing.Point(x, listView1.Controls[i].Location.Y);
listView1.Controls[i].Width = listView1.Columns[listView1.Columns.Count - 1].Width - 9;
}
}
if (listView1.Items.Count > 8)
{
listView1.Columns[listView1.Columns.Count - 1].Width -= 10;
}
listView1.Scrollable = false;
listView1.Scrollable = true;
resizing = false;
}
SetWindowTheme(listView1.Handle, "Explorer", null);
}
private void listView1_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
{
_listView1_Resize();
//int i = 0;
//for (i = 0; i < listView1.Columns.Count; i++)
//{
// if (listView1.Columns[i].Width < 20)
// listView1.Columns[i].Width = 20;
//}
}
}
}
Thanks!!
At the start of the resizing operation call listView1.BeginUpdate() and then call listView1.EndUpdate() when you're finished
This way windows won't redraw the control every time a change is made to it, or any of it's children and will redraw them all once when you call EndUpdate()