Problem in short: Load saved map that was saved as an textfile where 0 = empty button/tile, 1 = wall, 2 = character and it back up on another form.
Longer more detailed explanation:
I have been working on a winform game for a bit, I know it isn't the best way to make a game but I am just trying to get accustomed. Currently I have two forms, one to create a map, another to load it up. On my map creation form I am able to say the length and width of my map, when I generate it, it displays tiles(that are buttons) with the length and width dimensions specified( 3 buttons wide, 4 buttons long.)
Now I am able to save it as numbers that were given values for that certain image ( 0 is for no image just the button, 1 is for a button with an wall, 2 is for a button with a character.). What I am trying to do now is read the text file and load up the tiles with the correct dimensions and image that was originally given.
My images are placed onto radio buttons which determine which image to play, I did tags for this
public SaveForm()
{
InitializeComponent();
rNoImage.Tag = 0;
rNoImage.Click += Check;
rCharacter.Tag = 1;
rCharacter.Click += Check;
rWall.Tag = 2;
rWall.Click += Check;
}
private void square_Click(object sender, EventArgs e)
{
Map square = (Map)sender;
Map.Type = (MapType)selected;
switch (selected)
{
case 0:
square.Image = null;
break;
case 1:
square.Image = Properties.Resources.Character;
break;
case 2:
square.Image = Properties.Resources.Wall;
break;
}
}
private void Check(object sender, EventArgs e)
{
RadioButton toolBtn = (RadioButton)sender;
selectedTool = (int)toolBtn.Tag;
}
When saving I have done the following:
private void saveButton(object sender, EventArgs e)
{
SaveFileDialog sfg = new SaveFileDialog();
sfg.Filter = "Game File(*.game)|*.game";
if (sfg.ShowDialog() == DialogResult.OK)
{
using (StreamWriter sw = new StreamWriter(sfg.FileName))
{
sw.WriteLine($"{rows},{cols}");
foreach (Map square in (pnlGameBoard.Controls))
{
sw.WriteLine(square.GetString());
}
var output = MessageBox.Show("saved", "saved success", MessageBoxButtons.OK);
}
}
}
I have a component class set up for this called Map in this I have an enum to show the types
public enum MapType
{
None,
Character,
Wall,
}
Now I have my map being made as an Button, when clicked based on selected radio button image changes on the button.
public partial class Map : Button
{
int row;
int col;
public MapType Type { get; set; }
const int OFFSET = 20;
const int MapSize = 50;
public Map()
{
}
public Map(int row, int col)
{
this.row = row;
this.col = col;
this.Size = new Size(MapSize, MapSize);
this.Location = new Point(OFFSET + col * MapSize, OFFSET + row * MapSize);
Type = MapType.None;
}
public string GetString()
{
return $"{(int)Type}";
}
}
So I am able to save it, but my issue now is loading it up on the second form which I am struggling to do.
What I have managed so far is:
private void openButton_Click(object sender, EventArgs e)
{
OpenFileDialog ofg = new OpenFileDialog();
ofg.Filter = "Game File(*.game)|*.game;"
if(ofg.ShowDialog() == DialogResult.OK)
{
File.ReadAllLines(ofg.FileName);
//Not Sure what to do next here
}
}
Apologize for the lengthy post but I wanted to make sure that I am clear enough, thanks.
The layout for the textfile that I saved would be:
3,3
1
1
1
0
2
0
1
1
1
3,3 represents the length and width that was chosen, I will most likely remove this as I am only trying to read the numbers below, top row is wall,wall,wall(1,1,1), middle row is empty button, character, empty button, bottom row is wall,wall,wall.
I have looked at some different examples here that involve reading 2D matrixes from files to 2D int arrays but I am not sure how to actually implement this in my above code or how it works.
You've created a way to represent a Map as a string, but not the other way around. One way to create a Map from a string is to write a public static Map Parse(string input) method that takes in a string and returns a Map. One tricky part is that we will also need to pass in the row and col, since those are private fields and not settable outside of the constructor.
For example:
public class Map : Button
{
// Existing code exluded from this example
public static Map Parse(string input, int row, int col)
{
if (input == null) return null;
int typeVal;
if (!int.TryParse(input, out typeVal))
{
throw new ArgumentException("input must be a valid integer");
}
// Return a new map with row, col, and Type
return new Map(row, col) {Type = (MapType) typeVal};
}
}
Now that we can create a Map with the proper Type from a string (along with the row and col), we can create a couple of loops: one to loop through each row, and on each row we loop through each column, creating a Map and adding it to our panel:
// You might need to set some standard sizes for the Map controls
private int mapHeight = 50;
private int mapWidth = 300;
// Not sure where these are actually defined
private int rows;
private int cols;
private void openButton_Click(object sender, EventArgs e)
{
var ofg = new OpenFileDialog {Filter = "Game File(*.game)|*.game;"};
if (ofg.ShowDialog() == DialogResult.OK)
{
// Read all our lines into an array
var lines = File.ReadAllLines(ofg.FileName);
// And now do the opposite of how we created the text file:
// First, set the rows and cols based on the first line
// (some validation should be done here, but this works with "3,3")
var rowsCols = lines[0].Split(',');
int.TryParse(rowsCols[0], out rows);
int.TryParse(rowsCols[1], out cols);
// Next, create Maps from the rest of the lines and add them to our controls
// Note we should validate that lines.Length = rows * cols + 1
var line = 1; // This gets incremented below, so we read each line
for (int row = 0; row < rows; row ++)
{
for (int col = 0; col < cols; col++)
{
// Create a map from the line, row, and column using our new method
var map = Map.Parse(lines[line++], row, col);
// Set the layout by rows and columns (?)
map.Width = mapWidth;
map.Height = mapHeight;
map.Left = (col + 1) * mapWidth;
map.Top = (row + 1) * mapHeight;
// Hook up the Click event so our images load on click
map.Click += square_Click;
// Add the control to our panel
pnlGameBoard.Controls.Add(map);
}
}
}
}
Related
My instructions are: "Create a form that will display a running total of numbers a user enters." - to do this I've created a form with two text boxes (one for the number of values in the array and the other for the values in the array), a button to display it, and a label for it all to be displayed it. The issue is, is that my values aren't showing up - at all. My code is as below:
(** NOTE: I'm attempting to get the array to display in my label. txtInput is the inputted values and txtArrayValues is the number of elements.)
namespace Running_Total
{
public partial class frmEnter : Form
{
public frmEnter()
{
InitializeComponent();
}
private void btnDisplay_Click(object sender, EventArgs e)
{
int intNumber = Convert.ToInt32(txtArrayValues.Text);
string[] strArray;
strArray = new string[intNumber];
int i;
string j = "";
for (i = 0; i < intNumber; i++)
{
j = Convert.ToString(txtInput.Text);
strArray[i] += j;
}
lblDisplay.Text = strArray + " ";
}
}
}
Before, when I'd put lblDisplay.Text += j + " ";, it showed up in the label, but didn't pay any attention to the amount of elements the code was supposed to have. (Edit: this no longer works in my code.) (As is indicated in the title, I'm working with C# through Microsoft Visual Studio.)
It strongly depends on the fashion how the user inputs the numbers.
1) If he fills the textbox once with numbers and then presses the button to display them in the other box, it would suffice to use a string array catch the input and add it to the textbox or label that displays it. If he deletes the numbers in the input box and types new ones you could just repeat this step
namespace Running_Total
{
public partial class frmEnter : Form
{
// declare your Array here
string [] array = new string[1000];
int count = 0;
public frmEnter()
{
InitializeComponent();
}
private void btnDisplay_Click(object sender, EventArgs e)
{
// save input
array[count] = inputTextBox.Text;
count++;
// display whole input
string output = "";
for(int i = 0;i < count; i++)
{
output += array[i];
}
// write it the texbox
outputTextBox.Text = output;
}
}
Does that answer your question or do you have another input pattern in mind?
Looking at your code, I realized that you want to display same number enteted in txtInput text repeatedly up to as many times as a number entered in a txtArrayValues.Text. So for example txtArrayValues. Text = "5" and txtInput.Text="2", your code will yield result "2,2,2,2,2". If that is what you want then the following code will achieve that.
using System.Linq;
namespace Running_Total
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnDisplay_Click(object sender, EventArgs e)
{
int len, num;
if (int.TryParse(txtArrayValues.Text, out len) &&
int.TryParse(txtInput.Text, out num))
{
lblDisplay.Text = string.Join(",", new string[len].Select(x => txtInput.Text));
}
}
}
}
I am creating a Sudoku game with ASP.NET and C#. I am required to use classes and inheritance to build the structure entirely in the code-behind page (i.e. no asp:TextBox controls on the aspx page).
I am having an awful time trying to get my inputs to clear when I start a new game. I generate a new puzzle solution, but my previous boxes don't clear and I've tried everything I can think of.
Below are several chunks of code that relate to the problem.
The code that builds the puzzle and stores it in a Puzzle object.
private Puzzle newPuzzle(int[,] solution, int numbersVisible, int maxNumbersPerBox, int maxOccurancesPerNumber)
{
Puzzle newPuzzle = new Puzzle();
SudokuTextBox newTextbox;
Number newNumber;
Random randomRC = new Random();
//variable to hold the correct answer at the given location
int answer;
//variables to hold the location within the answers array
int rowLoc;
int colLoc;
//counter to count the number of times we while loop
int counter = 0;
//variables to hold the randomly-chosen rows & col values
int row;
int col;
//array to hold the positions of the numbers we are going to show
string[] show;
show = new string[numbersVisible];
while(counter < numbersVisible)
{
//generate random numbers that gives us the location of the numbers in the solution array that we are going to show
row = randomRC.Next(0, 9);
col = randomRC.Next(0, 9);
//if the random numbers are not already in the array
if (!show.Contains(row.ToString() + ":" + col.ToString()))
{
//add them to the array
show[counter] = row.ToString() + ":" + col.ToString();
//increase the counter
counter++;
} //end if...contains
} //end while
// BUILDING THE PUZZLE
//start looping through the puzzle rows
for (int pr = 0; pr < 3; pr++)
{
//another loop for puzzle columns
for (int pc = 0; pc < 3; pc++)
{
box = new Box(); //create a new Box object
//another loop for box rows
for (int br = 0; br < 3; br++)
{
//another loop for box columns
for (int bc = 0; bc < 3; bc++)
{
newTextbox = new SudokuTextBox();
newNumber = new Number();
//grab the answer to this particular SudokuTextBox from the solutions array
rowLoc = (pr + br + (2 * pr));
colLoc = (pc + bc + (2 * pc));
answer = solution[rowLoc, colLoc];
newNumber.setNumber(answer); //set the Number to the found answer
newTextbox.setTextBoxValue(newNumber); //fill in the textbox with Number
//if this SudokuTextBox is chosen to be given at the start of the puzzle
if (show.Contains((rowLoc + ":" + colLoc).ToString()))
{
//make this SudokuTextBox visible
newTextbox.setVisibility(true);
}
else {
newTextbox.setVisibility(false);
} //end if
box.setItem(newTextbox, br, bc); //add the SudokuTextBox to the correct position inside Box
} //end box column loop
} //end box row loop
newPuzzle.setItem(box, pr, pc); //add the Box to the correct position inside Puzzle
} //end puzzle column loop
} //end puzzle row loop
return newPuzzle;
} //end easy()
Storing the new puzzle in Session:
//when the Easy button is pressed
protected void btnEasy_Click(object sender, EventArgs e)
{
//generate a new random number
Random newRandomSoln = new Random();
//keep picking new solutions until we get one that's different than the last one
do
{
solution = chooseSolution(newRandomSoln.Next(1, 11));
}
while (solution == Session["solution"]);
//store the new solution
Session["solution"] = solution;
//generate a new puzzle
Session["puzzle"] = newPuzzle( (int[,])Session["solution"], 32, 4, 4 );
}
The code that builds the table structure, fills it with the answers stored in Puzzle, and adds it to the aspx page:
////////////////////////////////
// CREATING THE PUZZLE
///////////////////////////////
Table structure = new Table(); //table to be the outer structure of the puzzle
TableRow row; //row variable to make new rows
TableCell cell; //cell variable to make new cells
Table boxTable; //table that will hold individual Boxes
TableRow boxRow; //row that will hold 3 SudokuTextBoxes
TableCell boxCell; //cell that will hold a single SudokuTextBoxes
TextBox input; //textbox that will hold the textbox in SudokuTextBox
int answer; //int to hold the answer to a particular textbox
//start looping through the puzzle rows
for (int pr = 0; pr < 3; pr++)
{
row = new TableRow(); //create a new outer row
//another loop for puzzle columns
for (int pc = 0; pc < 3; pc++)
{
cell = new TableCell(); //create a new outer cell
boxTable = new Table(); //create a new inner table
box = new Box(); //create a new Box object
box = ((Puzzle)Session["puzzle"]).getItem(pr, pc); //find the box at the current location in the puzzle
//another loop for box rows
for (int br = 0; br < 3; br++)
{
boxRow = new TableRow(); //create a new inner row
//another loop for box columns
for(int bc = 0; bc < 3; bc++)
{
boxCell = new TableCell(); //create a new inner cell
textbox = new SudokuTextBox(); //create a new SudokuTextBox object
textbox = box.getItem(br, bc); //find the SudokuTextBox at the current location in the box
//grab the answer to this particular SudokuTextBox from the solutions array
answer = ((int[,])Session["solution"])[ (pr + br + (2 * pr)), (pc + bc + (2 * pc)) ];
input = textbox.getTextBox(); //grab the textbox inside SudokuTextBox and store it
input.MaxLength = 1; //only allow 1 character to be typed into the textbox
//give the textbox an ID so we can find it later
input.ID = ("tb" + (pr + br + (2 * pr)) + "_" + (pc + bc + (2 * pc))).ToString();
boxCell.Controls.Add(input); //add the textbox to the inner cell
boxRow.Controls.Add(boxCell); //add the inner cell to the inner row
} //end box column loop
boxTable.Controls.Add(boxRow); //add the inner row to the inner table
} //end box row loop
cell.Controls.Add(boxTable); //add the inner table to the outer cell
row.Controls.Add(cell); //add the outer cell to the outer row
} //end puzzle column loop
structure.Controls.Add(row); //add the outer row to the outer table
} //end puzzle row loop
pnlPuzzle.Controls.Add(structure);
////////////////////////////////
// end puzzle
///////////////////////////////
And the SudokuTextBox class code:
public class SudokuTextBox
{
private System.Web.UI.WebControls.TextBox textbox;
private bool visible;
private Number number;
public SudokuTextBox()
{
textbox = new System.Web.UI.WebControls.TextBox();
visible = false;
number = new Number();
} //end constructor
//function to make a new textbox
public System.Web.UI.WebControls.TextBox getTextBox()
{
return textbox;
}
//function to get the value of a textbox
public Number getTextBoxValue()
{
return number;
}
//????????????
public void setTextBoxValue(Number newNumber)
{
this.number.setNumber(newNumber.getNumber());
}
//function to get the visibility of a textbox
public bool getVisibility()
{
return visible;
}
//function to change the visibility of a textbox
public void setVisibility(bool newVisible)
{
if (newVisible)
{
//if the textbox is visible
//get the number
//and make it disabled
textbox.Text = number.getNumber().ToString();
textbox.ReadOnly = true;
textbox.BackColor = System.Drawing.Color.FromArgb(150, 148, 115);
} else
{
//if it is not visible
//hide the number
//and make it enabled
textbox.ReadOnly = false;
textbox.Text = "";
textbox.BackColor = System.Drawing.Color.White;
}
}
//function to change the color of the textbox if it is wrong
public void setWrongNumber()
{
textbox.BackColor = System.Drawing.Color.FromArgb(5, 156, 202, 252);
}
//function to change the color of the textbox if it is correct
public void setCorrectNumber()
{
//but don't change disable text boxes
if(textbox.ReadOnly != true)
{
textbox.BackColor = System.Drawing.Color.White;
}
}
//function to change the color of the textbox if it is blank
public void setBlankNumber()
{
//but don't change disable text boxes
if (textbox.ReadOnly != true)
{
textbox.BackColor = System.Drawing.Color.White;
}
}
//function to show the value of a textbox when clicking the "Hint" button
//also changes the color of the textbox so we know it was shown with a hint
public void setHint()
{
setVisibility(true);
}
} //end class
Thank you to all who gave your two cents. I just wanted to let everyone know that I have solved the issue:
I ended up separating out the code that builds the table structure, taking it out of Page_Load and putting it into its own function. I then called this function from Page_Load. I also called this function when I click the "new puzzle" button. I also added similar logic to that which I commented above to clear the previous table structure before building a new one:
foreach(Control c in pnlPuzzle.Controls){
pnlPuzzle.Controls.Remove(c);
}
I'm not exactly sure why this solve my problem, but it worked!
I have a task to develop Windows applications where paging is involved. If I perform any event like splitting date and time, it's applied only to the current page. I would like to apply that event to all pages in the Datagridview.
If I take a datatable/dataset and work on it, the UI is taking time to read the file as it again reads the whole file to data table. So, please suggest any other alternative to apply the events to all pages in the DataGridView.
I will post the code, or upload my code in any site or here, if required.
Please let me know if my question is unclear.
VARIABLES DECLARATION:
List<String> cmbList = new List<string>();
public String Replace;
public String Find;
public String Col;
public String NewColumn;
public String NewColumnValue;
public string MyFOrmat { get; set; }
int PageCount;
int maxRec;
int pageSize = 30;
int currentPage = 1;
int recNo = 0;
string FileName;
String[] datfile;
button1 = BROWSE BUTTON (Where i read the file):
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.InitialDirectory = "Desktop";
openFileDialog1.Filter = "dat files (*.DAT)|*.DAT|All files (*.*)|*.*";
openFileDialog1.FilterIndex = 2;
openFileDialog1.RestoreDirectory = true;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
FileName = openFileDialog1.FileName;
string text = System.IO.File.ReadAllText(FileName);
datfile = text.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
//Added on 2015-12-02
maxRec = datfile.Length - 1;
PageCount = maxRec / pageSize;
LoadPage(MyFOrmat);
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
}
LOADPAGE Code:
public void LoadPage(string Format, bool isFindAndReplace = false)
{
int startRec;
int endRec;
if (currentPage == PageCount)
{
endRec = maxRec;
}
else
{
endRec = pageSize * currentPage;
}
dataGridView1.Rows.Clear();
if (recNo == 0)
{
dataGridView1.Columns.Clear();
}
int rowindex = 0;
startRec = recNo;
for (int RowCount = startRec; RowCount <= endRec; RowCount++)
{
if (datfile[RowCount].ToString() != "" )
{
if (RowCount == 0)
{
string[] column = datfile[RowCount].Split('þ');
for (int i = 0; i < column.Length - 1; i++)
{
if (column[i].ToString() != "" && column[i].ToString() != "\u0014")
{
DataGridViewTextBoxColumn dgvtxtcountry = new DataGridViewTextBoxColumn();
dgvtxtcountry.HeaderText = column[i].ToString();
dgvtxtcountry.Name = column[i].ToString();
dataGridView1.Columns.Add(dgvtxtcountry);
cmbList.Add(column[i]);
i += 1;
}
}
}
if (RowCount != 0)
{
dataGridView1.Rows.Add();
string[] column = datfile[RowCount].Split('þ');
int index = 0;
for (int i = 1; i < column.Length - 1; i++)
{
if (column[i].ToString() != "\u0014")
{
if (i == 3)
{
dataGridView1.Rows[rowindex].Cells[index].Value = Convert.ToDateTime(column[i]).ToString(Format);
}
else
{ dataGridView1.Rows[rowindex].Cells[index].Value = column[i].Trim('þ'); }
index += 1;
i += 1;
}
}
rowindex += 1;
}
}
recNo += 1;
}
}
FIND and REPLACE Event:
private void btnFindandReplace_Click(object sender, EventArgs e)
{
Form2 f = new Form2();
f.cmbColumnCombo.DataSource = cmbList;
f.ShowDialog();
for (int i = 0; i <= dataGridView1.Rows.Count - 1; i++)
{
//dataGridView1.Rows[rowindex].Cells[index].Value = Convert.ToDateTime(column[i]).ToString(Format);
if (dataGridView1.Rows[i].Cells[f.cmbColumnCombo.Text].Value.ToString().ToLower().Contains(f.txtfind.Text.ToLower()))
{
//dataGridView1.Rows[i].Cells[f.cmbColumnCombo.Text].Value = dataGridView1.Rows[i].Cells[f.cmbColumnCombo.Text].Value.ToString().ToLower().Replace(f.txtfind.Text.ToLower(), f.txtreplace.Text);
//bulidDataRow(i);
if (!string.IsNullOrEmpty(f.txtfind.Text))
{
dataGridView1.Rows[i].Cells[f.cmbColumnCombo.Text].Value = dataGridView1.Rows[i].Cells[f.cmbColumnCombo.Text].Value.ToString().Replace(f.txtfind.Text, f.txtreplace.Text);
#region Commented
//dataGridView1.Rows[i].Cells[f.cmbColumnCombo.Text].Value = dataGridView1.Rows[i].Cells[f.cmbColumnCombo.Text].Value.ToString().Replace(f.txtfind.Text, f.txtreplace.Text);
//bulidDataRow(i);
#endregion
}
}
}
}
private void btnNext_Click(object sender, EventArgs e)
{
currentPage += 1;
if (currentPage > PageCount)
{
currentPage = PageCount;
//Check if you are already at the last page.
if (recNo == maxRec)
{
MessageBox.Show("You are at the Last Page!");
return;
}
}
LoadPage(MyFOrmat);
}
Please let me know if anything needs to be added.
To summarize your requirements:
You want to read largish data files of 10k - 500k records
You want to display them in chunks/pages in a DataGridView
You want allow the user to modify the data:
The user can merge columns
The user can use change&replace on the data
Date&time columns may be split
Possibly modified data shall be saved
The way I see it you have two approaches:
Either cache the data
Or cache the actions
Caching the actions is doable but clearly a lot more fuss, both in coding the caching and in keeping the data synchronized.
So caching the data would be my first choice.
Here is a sketch of how to break up the functionality:
A function to read in the whole data and load them into a DataTable
Functions for the initial display and for displaying a certain page
Functions for doing each of the changes on the list of rows.
After calling a changing function the current page display must be refreshed.
Keeping the total quantity of data in memory shouldn't really be a problem today; I notice that you are reading in all data as strings already in the datFile array. Reading it into a table will spare you to split it over and over..
A DataTable.DataRow also offers nice properies like HasErrors or RowState. And its Items can have a dedicated type to help with formatting..
Note however that DataRow doesn't have a (real) constructor; instead it must be created from a DataTable, so you will first have to create one from your columns!
The display code would use a pageSize and a currentFirstLine variable; it can clear and add the rows into the DGV or you could go for a binding solution with the DataTable you need anyway holding the DataRows and a filter on the table or rather on an BindingSource.
Of course you can also use a structure of your own, maybe a simple as a string[] or a List<string>to hold the row data..
If you are interested in the idea of caching the actions, you could create a ChangeAction class that holds:
the type
the parameters needed, ie, the column(s), the change&replace strings etc..
Then in a List<ChangeAction> you would store them as they happen and then apply them to each unchanged row. But here comes the first catch: You will need to know which row have been changed and maybe if a ChangeAction can be applied twice without screwing up the data.. More problems may or may not come later, depending on the details of you data and actions..
Here is an example of how to set up the binding using class level variables:
DataTable DT = new DataTable();
BindingSource BS = new BindingSource();
int pageSize = 0;
int firstLineVisible = 0;
After filling the table you can bind it and set the initial filer:
BS.DataSource = DT;
dataGridView1.DataSource = BS;
pageSize = (dataGridView1.ClientSize.Height - dataGridView1.ColumnHeadersHeight)
/ dataGridView1.Rows[0].Height;
int l1 = firstLineVisible; int l2 = firstLineVisible + pageSize;
BS.Filter = "Nr >= " + l1 + " and Nr < " + l2;
When scrolling you simply change the firstLineVisible and rest the Filter and the DataSource..
Now all your data modifications should work on the data in the DataTable using the SetField method!
Also note that you need one column in your data that holds a running number. If your data don't have one it is easy to include it by adding it to the data lines:
The column gets autogenerated in the DataGridView. For the DataTable we want to have it in the first data line; I use a separator string sep:
var lines = File.ReadAllLines(fileName).ToList();
..
string[] sep = { ";" };
var p0 = ("Nr" + sep[0] + lines[0]).Split(sep, StringSplitOptions.None );
DT.Columns.Clear();
for (int i = 0; i < p0.Length; i++) DT.Columns.Add(p0[i], typeof(string));
Adding it to the data is just as simple:
for (int l = 1; l < lines.Count; l++)
{
var p = (l + sep[0] + lines[l]).Split(sep, StringSplitOptions.None);
DT.Rows.Add(p);
}
You can hide the number column if you want to..:
dataGridView1.Columns["Nr"].Visible = false;
You should add that line right after setting the Filter.
I have placed a ListView on my main form.
I put 24 columns in it
I set the view to details
I have an array of integers like this
public static int[] myArrayOfIntegers = new int[24];
public static bool TheArrayIsNowReady = false;
int i;
int j;
int k;
string UserSeesThis;
Now for my request for help, please. There are 151 properties and 233 Methods associated with a ListView. Could someone please help me to understand how to place my 24 integers in this listview for the user to see them ?
if (TheArrayIsNowReady)
{
for (i = 0; i < 24; i++)
{
UserSeesThis = myArrayOfIntegers[i].ToString();
listView1._____what___do___I___put___here___[i] = UserSeesThis;
}
}
After doing one line, I'm going to have to put 500 more lines in the list box, and let the user scroll back through them. (We're hunting bogus numbers, if it matters)
In my dream app, I'll let the user scroll back five or six thousand lines.
The user is going to run a test, and an external box will send the PC 500 sets of 24 numbers. I want to put those on the screen for the user to see. I would like to be able to handle the same five and ten times over.
1) Create a listviewitem, ListViewItem item = new ListviewItem("firstvalue");
2) Create subitems for each column, item.SubItems.add("value");
3) Add item to list, listView1.Items.Add(item);
public static int[] myArrayOfIntegers = new int[24];
public static bool TheArrayIsNowReady = false;
int i, j, k;
string UserSeesThis = "?";
ListViewItem item;
private void Form1_Load(object sender, EventArgs e)
{
TheArrayIsNowReady = true;
if (TheArrayIsNowReady)
{
for (i = 0; i < 24; i++)
{
myArrayOfIntegers[i] = i;
if (i == 0) { item = new ListViewItem(myArrayOfIntegers[0].ToString()); }
item.SubItems.Add(myArrayOfIntegers[i].ToString());
UserSeesThis = "?";
}
listView1.Items.Add(item);
}
}
I would like to make a listview (detailed) with many similar items in it. To be more readable I would like it to have every listview.items.count % 2 == 0 row as backolor.lightgray.
I have made a listviewColumnSorter as described in this site:
http://support.microsoft.com/kb/319401
After some modification, so that the data looks "similar" to the one I need to use, my code is following:
public partial class Form1 : Form
{
private ListViewColumnSorter lvwColumnSorter;
public Form1()
{
InitializeComponent();
lvwColumnSorter = new ListViewColumnSorter();
this.listView1.ListViewItemSorter = lvwColumnSorter;
}
private void Form1_Load(object sender, EventArgs e)
{
ColumnHeader columnheader; // Used for creating column headers.
ListViewItem listviewitem; // Used for creating listview items.
// Ensure that the view is set to show details.
listView1.View = View.Details;
for (int i = 0; i < 10; i++)
{
listviewitem = new ListViewItem("item" + i.ToString());
if (listView1.Items.Count % 2 == 0)
{
listviewitem.BackColor = Color.LightGray;
listviewitem.SubItems.Add("xxx");
}
else
listviewitem.SubItems.Add("yyy");
this.listView1.Items.Add(listviewitem);
}
// Create some column headers for the data.
columnheader = new ColumnHeader();
columnheader.Text = "First Name";
this.listView1.Columns.Add(columnheader);
columnheader = new ColumnHeader();
columnheader.Text = "Last Name";
this.listView1.Columns.Add(columnheader);
// Loop through and size each column header to fit the column header text.
foreach (ColumnHeader ch in this.listView1.Columns)
{
ch.Width = -2;
}
}
private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)
{
// Determine if clicked column is already the column that is being sorted.
if (e.Column == lvwColumnSorter.SortColumn)
{
// Reverse the current sort direction for this column.
if (lvwColumnSorter.Order == SortOrder.Ascending)
{
lvwColumnSorter.Order = SortOrder.Descending;
}
else
{
lvwColumnSorter.Order = SortOrder.Ascending;
}
}
else
{
// Set the column number that is to be sorted; default to ascending.
lvwColumnSorter.SortColumn = e.Column;
lvwColumnSorter.Order = SortOrder.Ascending;
}
// Perform the sort with these new sort options.
this.listView1.Sort();
}
}
(+ the ListViewColumnsSorter class from msdn site.)
If you sort for the second column (Last name), you will see, that all xxx columns are grey and yyy are white, and as colors are seem to be bound to data, my original idea of having every second column grey, is now ruined.
Can I somehow keep the sorting function, and having always every second row grey, independent from the data?
pic:
So to be perfectly clear, after sorting in any column, I would like to keep every second row Lightgrey. How to achieve this?
(.net 4)
This is soooo typical. I googled and tried 2 hours before posting this, and found the answer 10 minutes later...
Alternate Color in ListView C# (.Net 3.5)?
Simply add
recolorListItems(listView1);
to the end of the listview1_columnClick function. where:
private static void recolorListItems(ListView lv)
{
for (int ix = 0; ix < lv.Items.Count; ++ix)
{
var item = lv.Items[ix];
item.BackColor = (ix % 2 == 0) ? Color.LightGray : Color.White;
}
}
Sorry for these extra posts