I am trying to create a foreach loop for a listview to detect which items are selected (multiselection is on) and then concatenate the item's text to a string to pass to a second page with the frame.navigate method.
I've googled and several solutions on here suggest using the listview.CheckedItems or .SelectedItems, some older ones referenced .IsSelected or .IsChecked. none of these seem to be valid in the Visual Studios version I'm using. I've used the updater to ensure I have the most recent version Visual Studios.
To be clear: I'm not asking for someone to rewrite my homework, but to find out what the working replacement for listview.checkeditems is, or if this simply no longer works what should I be using instead of a listview for the user to select items that I can detect.
Here are the instructions to my homework.
Create two arrays ( 20 elements). The first array will contain all of the items available including a Distinguisher between breakfast, lunch and dinner, the item description and the price. Populate this array though a loaded event method.
On the first page, provide three buttons to choose breakfast, lunch or dinner. When the user clicks a button, have the items for that meal description( no price) appear in a listview box on top portion of the page and also record them in the second array.
Add a checkout button to the page. When clicked go to a second page.
On the second page, display the items selected ( already stored in second array) including price in a list view box. Provide the total of cost of the items.
Everything up to the checkout button works. I've populated the array from a text file, the meal buttons load the appropriate foods into the listview and I know how to pass strings with Frame.Navigate but if I can't detect what Listview items are checked I can't pass them!
I have done a LOT of google searching to find a solution, we have no textbook for this class and the teachers answer is to re-watch some tutorial videos (half of which are for windows 8 phones and are no longer entirely correct).
Here is the snippet of code for my checkout button
private void CheckoutButton_Click(object sender, RoutedEventArgs e)
{
foreach (ListViewItem eachItem in MenuList.CheckedItems)
{
checkedMenuItems = checkedMenuItems + "/" + MenuList.Items.ToString();
}
}//end CheckoutButton_Click
The error returned for CheckedItems is
'ListView' does not contain a definition for 'CheckedItems' and no extension method 'CheckedItems' accepting a first argument of type 'ListView' could be found (are you missing a using directive or an assembly reference?)
The same error is returned for SelectedItems and no solutions are suggested by Visual Studios.
I am hoping that someone can help!
Thanks.
I'm adding the code for the whole MainPAge in case it is relevant. It references class (breakfast, lunch, dinner) in a separate .cs file.
public sealed partial class MainPage : Page
{
public static meal[] menuItems = new meal[20];
public static meal[] menuChoices = new meal[20];
public string checkedMenuItems;
public MainPage()
{
this.InitializeComponent();
Loaded += PopulateArray;
}
public async void PopulateArray(object sender, RoutedEventArgs e)
{
int counter = 0;
char switchCheck;
var file = await StorageFile.GetFileFromApplicationUriAsync(new
Uri("ms-appx:///MenuItems.txt"));
using (var inputStream = await file.OpenReadAsync())
using (var classicStream = inputStream.AsStreamForRead())
using (var streamReader = new StreamReader(classicStream))
{
while (streamReader.Peek() >= 0)
{
string itemIn = string.Format(streamReader.ReadLine());
string[] item = itemIn.Split('/');
switchCheck = Convert.ToChar(item[0]);
switch (switchCheck)
{
case 'b':
menuItems[counter] = new
breakfast(Convert.ToChar(item[0]), item[1], Convert.ToDecimal(item[2]));
// MenuList.Items.Add("works item# " + counter +
menuItems[counter].getMealType());
break;
case 'l':
menuItems[counter] = new
lunch(Convert.ToChar(item[0]), item[1], Convert.ToDecimal(item[2]));
break;
case 'd':
menuItems[counter] = new
dinner(Convert.ToChar(item[0]), item[1], Convert.ToDecimal(item[2]));
break;
}//end switch
counter++;
}//end while`
}
}//end populateArray method
private void BreakfastButton_Click(object sender, RoutedEventArgs e)
{
MenuList.Items.Clear();
for (int i = 0; i < menuItems.Length && menuItems[i] != null; i++)
{
if (menuItems[i].getMealType() == 'b')
MenuList.Items.Add(menuItems[i].getMealDesc());
}//end for loop
}//end BreakfastButton_Click
private void LunchButton_Click(object sender, RoutedEventArgs e)
{
MenuList.Items.Clear();
for (int i = 0; i < menuItems.Length && menuItems[i] != null; i++)
{
if (menuItems[i].getMealType() == 'l')
MenuList.Items.Add(menuItems[i].getMealDesc());
}//end for loop
}//end LunchButton_Click
private void DinnerButton_Click(object sender, RoutedEventArgs e)
{
MenuList.Items.Clear();
for (int i = 0; i < menuItems.Length && menuItems[i] != null; i++)
{
if (menuItems[i].getMealType() == 'd')
MenuList.Items.Add(menuItems[i].getMealDesc());
}//end for loop
}//end DinnerButton_Click
private void CheckoutButton_Click(object sender, RoutedEventArgs e)
{
foreach (ListViewItem eachItem in MenuList.CheckedItems)
{
checkedMenuItems = checkedMenuItems + "/" +
MenuList.Items.ToString();
}
}//end CheckoutButton_Click
}//end mainpage
From your description I could not clearly identify what type your object MenuList is.
According to the reference you could use the SelectRange method to solve this problem.
This might link help you: ListViewBase.SelectedItems Property
It seems there is a similar issue here, you can refer my answer there.
C# UWP Passing Data From One ListView To A Second Listview on the Next Page in a Array
Related
I am using C# Windows Forms and a codefirst database (Visual Studio 2013 Ultimate).
Is it possible to display a list inside another list in Windows Forms? (The emphasis is on -displaying- the data).
Please see this project as an example: https://postimg.cc/image/inunj8pxh/
I usually display a list with powerpacks´ datarepeater. For example when an order is placed by a customer, I can display the orderId, customerEmail, customerName etc. of the list of orders.
However, each order includes many different items. So far, I am not able to display any elements of the child-list (items) inside each element the datarepeater, where the parent-list (orders) is shown. The foreign-key of each item is the orderId, and the foreign-key of the order is the list of items (relationship order...items is 1..n).
I found the solution! It took me a while to figure out how to gain control over datarepeater items. Reading across many other forums and tutorials, I gradually worked my way through. Find in the screenshot my complete project:
http://i.stack.imgur.com/jFa7G.png
Any improvements in the code are more than welcome. Since I am quite new to the whole programming world, my code may not be optimized and the use of vocabulary may sometimes be inaccurate.
Here you find the code of my Form1:
namespace list_inside_list
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
protected override void OnLoad(EventArgs e)
{
//First we load the list of Orders to datarepeater1
Program.CompanyContext _context = new Program.CompanyContext();
List<list_inside_list.Program.Order> listOrders = _context.Order.ToList();
program_OrderBindingSource1.DataSource = listOrders;
//I don´t know why, but we need to load the list of items as well, although we never use the listItems variable
List<list_inside_list.Program.Item> listItems = _context.Item.ToList();
/*
* 1. We will loop through all the datarepater1 items (which is fed with listOrders)
* 2. We assign currItem as datarepeater1.CurrentItem in order to "select" the current item at index j,
* although we will never user currItem
* 3. We tell the program that of the current datarepeater item we want use the current Order object
* 4. We go through each of the currentOrder.items and print the itemName
*
*/
DataRepeaterItem currItem = new DataRepeaterItem();
for (int j = 0; j < this.dataRepeater1.ItemCount; j++)
{
this.dataRepeater1.CurrentItemIndex = j;
currItem = dataRepeater1.CurrentItem;
var currentOrder = (list_inside_list.Program.Order)program_OrderBindingSource1.Current;
foreach (var item in currentOrder.items)
{
dataRepeater1.CurrentItem.Controls["richTextBox1"].Text
= dataRepeater1.CurrentItem.Controls["richTextBox1"].Text + item.itemName + "\n";
}
}
}
}
}
newbie programmer here after hours of searching has left me stumped.
I'm having trouble with referencing a control inside a tab created at RunTime with a button press. Basically what I have is a tabletop RPG calculator, using a Windows Form, that has a tabControl holding tab pages, with each tab page holding user-inputted stats for that individual enemy to be used in calculations.
The problem is that I want the user to be able to click a button to generate a new enemy tab page. Here is my code for generating an enemy tab page with a TextBox.
int enemyNumber = 0;
// Creates a new Enemy Tab
private void button2_Click_1(object sender, EventArgs e)
{
// Create a new TabPage
var newTabPage = new TabPage()
{
Text = "Enemy " + enemyNumber,
};
// Add Enemy Name Box
var newEnemyNameBox = new TextBox()
{
Name = "enemyNameBox" + enemyNumber,
Text = "",
Location = new Point(127, 11),
Size = new Size(133, 20)
};
// Add the controls to the new Enemy tab
newTabPage.Controls.Add(newEnemyNameBox);
// Add the TabPage to the TabControl
tabControl1.TabPages.Add(newTabPage);
// Increases the enemy's "reference number" by 1
// So that enemy tabs will be generated in order enemyTab0, enemyTab1, etc.
enemyNumber += 1;
}
This all works nicely. Unfortunately, after this point things have gotten ugly. I need to reference that TextBox named "enemyNameBox" + enemyNumber, and I'm not sure how to do so.
What I did was create "archVariables" to store the values from whatever enemy tab is selected, then use the appropriate archVariable in the program's calculations. IE: archEnemyName. The idea is that whatever tab the user is currently selected on (determined via SelectedIndex) the TextBox from that page will be used for the program's output.
Here are the two things I've tried after researching the matter:
// Attempt 1
private void defendCalcButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < tabControl1.SelectedIndex; i++)
{
archEnemyNameBox = ((TextBox)Controls["enemyNameBox" + i]).Text;
}
}
This code simply throws a NullReferenceException when I press the button. So after researching more I tried this:
// Attempt 2
private void defendCalcButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < tabControl1.SelectedIndex; i++)
{
TextBox tb2 = new TextBox();
tb2 = ((TextBox)(enemyTab.Controls.Find("enemyNameBox" + i, true)));
archEnemyNameBox = tb2.Text;
}
}
This time I got an Error: Cannot convert type 'System.Windows.Forms.Control[]' to 'System.Windows.Forms.TextBox'
I feel like the second method I have here is probably closer to the correct way to do this, but apparently I'm still not getting it right. I've learned a lot by searching the information on stackoverflow and msdn.microsoft but nothing has gotten me past this problem.
Any help would be appreciated.
basically the problem with your second attemp is that enemyTab.Controls.Find("enemyNameBox" + i, true) returns an array of Controls Control[] and you're trying to convert that to a Control here is the problem, you should get the first control in that array and then convert it to a Control so it should be like this:
private void defendCalcButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < tabControl1.SelectedIndex; i++)
{
TextBox tb2 = new TextBox();
tb2 = ((TextBox)(enemyTab.Controls.Find("enemyNameBox" + i, true)[0]));
archEnemyNameBox = tb2.Text;
}
}
but it is not the BestWay to do so it seems that everytime a user adds a new tabPage it will have the same Controls right? so why not create an userControl with any Control you have on your TabPage? so when you press the user press to add a new tab your code should be like so:
private void CreateNewEnemyTab()
{
var newTabPage = new TabPage()
{
Text = "Enemy " + enemyNumber,
};
EnemyTabUserControl enemyTab = new EnemyTabUserControl(enemyNumber);
here the EnemyTabUserControl should have all the components you need;
newTabPage.Controls.Add(enemyTab);
tabControl1.TabPages.Add(newTabPage);
}
and the code to bring the TextBox from the current tab could be as follow (you are going to need to reference LINQ)
using System.Linq;
//First Lets create this property, it should return the selected EnemyTabUserControl inside the tabControl
public EnemyTabUserControl CurrentTab {
get {
return tabControl1.SelectedTab.Controls.OfType<EnemyTabUserControl>().First();
}
}
// then if we make the textbox you want to reference from outside the code we can do this
CurrentTab.NameOfTheTextBox;
Patrick has solved your fundamental problem, but I don't think you need the loop in there at all. Here I've broken the steps out so you can see what needs to happen a little better:
private void defendCalcButton_Click(object sender, EventArgs e)
{
Control[] matches = this.Controls.Find("enemyNameBox" + tabControl1.SelectedIndex.ToString(), true);
if (matches.Length > 0 && matches[0] is TextBox)
{
TextBox tb = (TextBox)matches[0];
archEnemyNameBox = tb.Text;
}
}
I'm a C# student and I'm a little stuck at on my midterm project.
I dropped my project and spec here: https://www.dropbox.com/sh/eo5ishsvz4vn6uz/CE3F4nvgDf
If you run the program, it will come to the last area I left off at..
private void btnAddScore_Click(object sender, EventArgs e)
{
for (int i = 0; i < 3; i++)
{
tempScore = Convert.ToDecimal(txtScore.Text);
Form1.scoreList = tempScore; (was Form1.scoreList[i] = tempScore;)
}
txtScoresList.Text += Convert.ToString(tempScore) + " ";
}
There's a main form, a secondary add form, and a third and fourth form, all the controls are in place, just the wiring is what's left over.
(1) In the above code, there are supposed to be 3 scores passed to the main form, which, along with a student name string, are to populate the ListBox on the main form. I can't figure out how to access that ListBox, anytime I type "listStudents" nothing happens.
(2) I'm also not sure how to limit an input of only 3 scores when I'm clicking the "add" button 1 time, which means I know my for loop is probably completely wrong. I don't know if I should save those scores to an array, list, or individual vars, being that it can be 3 (or more, but 3 is fine) scores.
(3) When I hit "OK" on the AddNewStudent form, do I write my code there to populate the main form ListBox, or does it go in the main form?
Update:
private void Form1_Load(object sender, EventArgs e)
{
lbStudents.Items.Clear();
//something like
foreach (decimal i in scoreList2)
{
scoreList = scoreList2.ToString(); //gives me a cannot implicitly convert error
}
lbStudents.Items.Add(tempInfo1 + " " + scoreList2);
}
//I want the listbox to populate like "Name - |100| |90| |80|"
This code seems to me, to be correct, for getting the ListBox populated, but I'm unsure of how to add the entire contents of the list to a string, and then add that to the listbox.
This will get your code building and running.
Change the following declaration in form1
public static decimal[] scoreList = new decimal[3];
to
public static List<decimal> scoreList = new List<decimal>();
and update your btnAddScore_Click handler to
//save scores to temp static var, populate noread txtbox txtScoresList with scores
for (int i = 0; i < 3; i++)
{
//save score to static var for trans-form data sending
tempScore = Convert.ToDecimal(txtScore.Text);
Form1.scoreList.Add(tempScore);
}
The rest is not too difficult, you should be able to work it out.
I've created a custom wizard that generates a windows form through code that lists out some SQL queries for the user. For almost all of the testing of the form and the wizard itself, adding it to a blank project would bring up the form and I could test the button click events and other general form stuff. Most recently I fleshed out the listbox's event listeners and ever since then I get this error:
Googling has lead me to a lot of posts about Ruby, which I'm not using. Other suggestions were reboot and re installation, and those proved unsuccessful. I attempted to comment out the listbox events but that did not keep the error from occuring, however, if it helps here are the events in question:
//-----------Event fired when a listbox object is double-clicked; populate the listbox with the new databases---------
public void dataList_MouseDoubleClick(object sender, EventArgs e)
{
//temp string used to hold the name of the clicked object
string selectedNAME = dataList.SelectedItem.ToString();
firstSEL.TableVar = selectedNAME;
foreach (tempDataVar t in dataVars)
{
if (t.TableVar == firstSEL.TableVar)
{
firstSEL = t;
}
}
string newQ = "SELECT COLUMN_NAME,* FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + firstSEL.TableVar + "' AND TABLE_SCHEMA= '" + firstSEL.SchemaVar + "'";//order by TABLE_NAME'";
results = GetDataSet(bldr.ToString(), newQ);
//listBox1.Items.Clear();
foreach (DataRow row in results.Tables[0].Rows)
{
//foreach (object x in row.ItemArray)
//{
// listBox1.Items.Add(x.ToString());
//}
for (int x = 0; x < row.ItemArray.Length; x++)
{
if (x == 0)
{
colList.Items.Add(row.ItemArray[x]);
}
}
}
dataList.Enabled = false;
}
//-----------------------------Event that fires when the index of the second listbox changes--------------------------
private void colList_SelectedIndexChanged(object sender, EventArgs e)
{
btnYes.Enabled = true;
}
Noobie mistake fixed by a co-worker! I blindly copied and pasted the following code from a "How to make a wizard tutorial":
[ComVisible(true)]
[Guid("20184B81-7C38-4E02-A1E3-8D564EEC2D25"),
ProgId("MyNewWizard.Class1")]
This code needed to be directly above the MyNewWizard class and I accidentally pasted in my custom TempDataVar class in the white space between these lines and the start of the MyNewWizard class. If you're receiving a similar error then I'd suggest testing around the order of some of your attributes/classes!
I am using two forms, where one is a rich text editor with menus and a rich text box and the second form is for search and replace and contains four button and two text boxes. I have managed to do the find button but I am having problems with Find Next. I am using C# Windows Forms.
Here is the code I am using for Find:
private void button1_Click(object sender, EventArgs e)
{
RichTextBox frm1TB = ((Form1)this.Owner).txtDisplay;
int foundAt = frm1TB.Text.IndexOf(searchText.Text);
if (foundAt == -1)
{
MessageBox.Show("Not Found");
}
else
{
frm1TB.SelectionStart = foundAt;
frm1TB.SelectionLength = searchText.TextLength;
frm1TB.Focus();
}
}
Find next would be something like the following:
if (frm1TB.Text.Length >= frm1TB.Text.SelectionStart + frm1TB.Text.SelectionLength)
{
int foundAt = frm1TB.Text.IndexOf(
searchText.Text,
frm1TB.Text.SelectionStart + frm1TB.Text.SelectionLength);
}
You need to remember index at which you found your previous entry (or even better, at which you should start find next search) and then simply use IndexOf(string, int) overload, which allows you to start search at specified position. First, simply add next search start index field to your class:
private int nextSearchStartIndex;
Now, your Find method needs to keep update this index appropriately:
if (foundAt == -1)
{
this.nextSearchStartIndex = 0;
MessageBox.Show("Not Found");
}
else
{
this.nextSearchStartIndex = foundAt + searchText.TextLength;
// ...
}
And FindNext becomes trivial:
// ...
var foundAt = frm1TB.Text.IndexOf(searchText.Text,
this.nextSearchStartIndex);
// Here you can use exactly same update index logic as in Find
You can't use the IndexOf() method for it, you have to switch to Regular Expressions.
Here is an example how you can easily get all the search entries in RichtBox.Text:
using System.Text.RegularExpressions;
Regex re = new System.Text.RegularExpressions.Regex(searchText.Text.ToString(),RegexOptions.None);
MatchCollection mc = re.Matches(frm1TB.Text.ToString());
foreach (var ma in mc)
{
//do what you want
}