I'm currently using Microsoft's Visual Studio 2019 and I'm trying to make a version of tic-tac-toe that allows the user to select the size of the board (3x3, 4x4, 5x5, etc...). I'm using buttons for the user input and I'm stuck on how I would go about initializing the needed buttons depending on the size of the board.
if (ThreeByThree)
{
for(int i = 1; i <= 9; i++)
{
Button ("btn" + i) = new Button();
}
This is the only way I could think about doing this but this results in an error, if anyone has encountered this issue I would appreciate some advice.
You can't dynamically create variable names, but you could add items to a list of buttons:
List<Button> buttons = new List<Button>();
if (ThreeByThree)
{
for(int i = 1; i <= 9; i++)
{
buttons.Add(new Button());
}
}
You can then reference the buttons by index - e.g. buttons[0] through buttons[8]
Related
So I have this idea of adding several buttons to a grid, then arranging them, and the number of buttons added is related to a number I enter. All works fine, until I try to make it work under MVVM.
Code that works in the MainWindow.xaml.cs:
private void Button_Click(object sender, RoutedEventArgs e)
{
int i = 0, j = 0;
Brush[] bs = { Brushes.BurlyWood, Brushes.Honeydew };
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
Button btn = new Button();
btn.Height = 50;
btn.Width=50;
btn.SetValue(Grid.RowProperty, i);
btn.SetValue(Grid.ColumnProperty, j);
if ((i + j) % 2 == 0)
{
btn.Background=bs[0];
}
else btn.Background = bs[1];
GameGrid.Children.Add(btn);
}
}
}
So basically, I press a button and it adds 3x3 buttons, colored nicely and spread appropriately. But then I get to the MVVM:
private void ButtonClickCommand()
{
RowCount = GridNumber;
ColumnCount=GridNumber;
int i = 0, j = 0;
Brush[] bs = { Brushes.BurlyWood, Brushes.Honeydew };
for (i = 0; i < GridNumber; i++)
{
for (j = 0; j < GridNumber; j++)
{
Button btn = new Button();
btn.Height = 50;
btn.Width = 50;
// btn.Command = StartCommand; Ill add that later
btn.SetValue(Grid.RowProperty, i);
btn.SetValue(Grid.ColumnProperty, j);
if ((i + j) % 2 == 0)
{
btn.Background = bs[0];
}
else btn.Background = bs[1];
somebuttonlist.Add(btn);
}
}
}
Here I have a List of buttons, which should accept the new created buttons, then transfer them to the grid. Code of the button list:
private List<Button> _bslist = new List<Button>();
public List<Button> somebuttonlist
{
get
{
return _bslist;
}
set
{
_bslist = value;
NotifyPropertyChanged();
}
}
And xaml code:
<ItemsControl ItemsSource="{Binding somebuttonlist}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Name="GameGrid" Visibility="{Binding GameVis}"
vm:GridHelpers.RowCount="{Binding RowCount}"
vm:GridHelpers.ColumnCount="{Binding ColumnCount}">
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Don't mind all the bindings, they work properly when I use the non-MVVM format.
So how do I properly transfer the working code into the View Model? Is there a way to access the children accordingly?
It looks like you are binding to a List, which does not notify when new records are inserted or any record is deleted. The NotifyPropertyChanged() that you have only kicks off when the reference to that list is modified, so for example, setting it to a new List() or a different List. Try changing it to an ObservableCollection instead, which sends an event for when the number of records in the collection get modified.
This is not the right way of doing things with MVVM. What you are trying to do now is to pull visual code into your ViewModel. Ideally, ViewModels should leave in a separate project without any references to visual stuff. This way, referencing Button will result in broken code unless you add a reference for System.Windows.Controls and this reminds you that you do things the wrong way.
What you are trying to do is doable in pure MVVM way, but will result in much more code, which also be convoluted to you if you haven't got a grasp on MVVM yet. Also note, that in real life, it is acceptable to have some code behind for complicated scenarios. For this you just create a custom control to encapsulate all code behind logic.
The nice solution in your case can be a custom control, that encapsulates Grid and logic to populate it with buttons. You also add dependency properties for Rows and Columns, so you can bind to them in XAML, and define a command which is invoked when button is clicked. This may be a good example: How to create bindable commands in Custom control?
In my program i'm currently working on programmatically adding a variety of form objects in C#. For example i'm trying to create a certain group of panels, which contain the data I wish to show. When loading the form I have a file which contains all of the data I wish to load in, the loading itself works fine but when loading I need to create a variety of form labels, panels and images to display all of the necessary data and as such I need to make these panels and labels all with a seperate name, but programmatically.
for (int i=0; i<fileLength; i++)
{
Panel pnl = New Panel();
pnl.Name = "pnl1"+i;
//Set the other properties here
}
What i'm trying to do if use an iterator to append the current iteration to the end of the name. Am I going the right way about it? Or should I be doing a different method?
You cannot change variable/object name at runtime. If you want to write code against the object than you need to keep a reference to it. In your case you have changed the Name property of Panel but still you have to use it as pnl, not as pnl0 or pnl1.
The other way for doing this would be to use a Dictionary with key as the name as you assign and value as the object itself. This will help you in accessing your controls using its name that you have assigned to it.
Dictionary<string, Panel> panels = new Dictionary<string, Panel>();
for (i = 0; i <= 10; i++) {
Panel pnl = new Panel();
panels.Add("pnl" + i.ToString(), pnl);
}
//write code against panels
panels("pnl0").Width = 100;
For accessing within loop:
foreach (string pnlName in panels.Keys) {
panels(pnlName).Visible = true;
}
for (i = 0; i <= 10; i++) {
panels("pnl" + i).Visible = true;
}
I have a c# windows form application.I have 2 charts in my windows form. i also have a combobox and two buttons among others. What i want is according to the text of the combobox, when i press the start button to load different graphs. So at button start event according to value of combobox i call a different function that loads the charts with what i want each time. And the second button , the stop button has the code below in order to clear the charts.
chart1.Series.Clear();
chart2.Series.Clear();
Sometimes my code runs ok but there are times that it throws the error
" A chart element with the name 'kwh_price' already exists in the 'SeriesCollection'." My code for load the chart is:
string[] seriesArray = { "kwh_price", "p_cost" };
for (int i = 0; i < seriesArray.Length; i++)
{
this.chart1.Series.Add(seriesArray[i]);
this.chart1.Series[seriesArray[i]].BorderWidth = 7;
}
Am i doing something wrong??is there something more needed in order to clear the chart?? And i don't understand why sometimes it runs ok and others not.
Put the clear code in before the load code. That way you can be sure the data is cleared before adding new data.
chart1.Series.Clear();
chart2.Series.Clear();
string[] seriesArray = { "kwh_price", "p_cost" };
for (int i = 0; i < seriesArray.Length; i++)
{
this.chart1.Series.Add(seriesArray[i]);
this.chart1.Series[seriesArray[i]].BorderWidth = 7;
}
I don't know whether it is clear. I mean a form has an input textbox and a button. If I input 5 in the textbox and click on the button, the form will add 5 labels...
The question is I don't know it is 5 or 4 or 3……before the code is running and the input.
I don't know how to add the labels and how to define or get their names in order to use them later in the code.
I am just learning windows applications development with VS using C#....
And also this is my first ask in stackoverflow please forgive me if it is not clear. Is there anybody can help me?
let's split your entire problem into few steps of understanding:
What basically down the line, you are asking, is to how to add controls dynamically in a winform, in your case the control is label, so wrap your label creating logic in a function like below:
protected Label CreateLabel(string Id, string text)
{
Label lbl = new Label();
lbl.Name = Id;
lbl.Text = text;
return lbl;
}
Now you need to add as many labels as the number entered in a given textBox and upon a button click, so possibly something like below in button's click event:
protected void button_Clicked(object sender, EventArgs e)
{
//make sure nothing invalid string comes here
int counter = Convert.ToInt32(txtCount.text);
for(int i=0;i<counter;i++)
{
var lbl = CreateLabel("rand"+i, "Label" +i);
container.Controls.Add(lbl);//container can be your form
}
}
Now the basic problem in winforms you will face, will be about the positioning of these dynamically added labels. The most simple way to go about it is to add your labels to winforms FlowLayoutPanel. It automatically aligns the controls. There are other layout controls available aswell. so do this :
drag and drop a FlowLayoutPanel on your form and give it the name "container", rest assured
For example:
for(var i=0; i<N; i++ ) {
var l= new Label();
l.Text = "some name #" + i.ToString();
l.Width = 200;
l.Location = new Point(30, 20);
parent.Controls.Add(l);
}
You can use this as:
Label[] arrLabel;
int num = 0;
int.TryParse(textBox1.Text, out num);
arrLabel = new Label[num];
for (int i = 0; i < num; i++)
{
arrLabel[i] = new Label();
arrLabel[i].Text = "Label #" + (i+1);
arrLabel[i].Width = 20;
arrLabel[i].Location = new Point(30+10*(i+1), 20);
this.Controls.Add(arrLabel[i]);
}
I work on windows application. It has one form in application which displays check boxes in check box list, here is the screen shot of form
It's single from of my application which i display in different languages And also my windows application is made in multiple languages Like English, German, Japanese etc..
My problem is that how to display translated text of check box in check box list
Here is my code :
this.checkedListBox1.FormattingEnabled = true;
this.checkedListBox1.Items.AddRange(new object[] {
"Select All",
"Amplitude1",
"Amplitude2",
"Amplitude3",
"Amplitude4",
"Amplitude5",
"Amplitude6",
"Amplitude7"});
this.checkedListBox1.Location = new System.Drawing.Point(96, 55);
this.checkedListBox1.Name = "checkedListBox1";
this.checkedListBox1.Size = new System.Drawing.Size(123, 124);
this.checkedListBox1.TabIndex = 8;
this.checkedListBox1.SelectedIndexChanged += new System.EventHandler(this.ckbselectall_CheckedChanged);
I made a single file to translate text of form, i put that code below where LCheckBox is my file from where i translate the text of check box in check box list
this.checkedListBox1.FormattingEnabled = true;
this.checkedListBox1.Items.AddRange(new object[] {
LCheckBox.SELECTALL,
LCheckBox.Amplitude1,
LCheckBox.Amplitude2,
LCheckBox.Amplitude3,
LCheckBox.Amplitude4,
LCheckBox.Amplitude5,
LCheckBox.Amplitude6,
LCheckBox.Amplitude7});
this.checkedListBox1.Location = new System.Drawing.Point(96, 55);
this.checkedListBox1.Name = "checkedListBox1";
this.checkedListBox1.Size = new System.Drawing.Size(123, 124);
this.checkedListBox1.TabIndex = 8;
this.checkedListBox1.SelectedIndexChanged += new System.EventHandler(this.ckbselectall_CheckedChanged);
But it gives me some error message
you can ask for the language at the begining and then create the checkbox list depending on the language. u can use different if cases for each language
In code I just use the items collection to modify the desired item.
So lets say you have a form with a button on it. When the button is clicked
you want to add one to all the items in the list, then the code to do that
would look as found below assuming that the listbox was named "_list" and
the button was named "_button."
private void FillList()
{
_list.BeginUpdate();
_list.Items.Clear();
for(int i =0 ; i <=9; i++)
_list.Items.Add(i);
_list.EndUpdate();
}
private void _button_Click(object sender, System.EventArgs e)
{
_list.BeginUpdate();
ListBox.ObjectCollection items = _list.Items;
int count = items.Count;
for(int i = 0; i < count; i++)
{
int integerListItem = (int)items[i];
integerListItem ++;
// --- Update The Item
items[i] = integerListItem;
}
_list.EndUpdate();
}