Populating Listbox with items from an array C# WPF - c#

I have created an array of string in an xaml file that I need to use as items in a c# wpf ListBox control. I've tried all kinds of ways to get the items from the array to add to the ListBox, but to no avail. Here's my code:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>DocumentSettings.DepositRuntimeDefaults</string>
<string>DocumentSettings.LendingCustomization.CommonSettings</string>
</ArrayOfString>
That's the array, now in my code behind I have a singleton that creates a list:
using System.Collections.Generic;
using System.IO;
namespace csi.Framework.Business
{
public class UIPathOptionsManager
{
public static UIPathOptionsManager Instance = new UIPathOptionsManager();
public List<string> UIPathOptions;
public string theUIPathOptionsFile { get; set; }
public void Initialize(string theDirectory)
{
theUIPathOptionsFile = theDirectory + "\\UIPathOptions.xaml";
if (File.Exists(theUIPathOptionsFile))
{
System.Xml.Serialization.XmlSerializer xmlDeserializer = new
System.Xml.Serialization.XmlSerializer(typeof(List<string>));
TextReader fileReader = new StreamReader(theUIPathOptionsFile);
UIPathOptions = (List<string>)xmlDeserializer.Deserialize(fileReader);
fileReader.Close();
}
}
}
}
And from there I have a ListBox class that I need to populate:
ListBox theUIPathOptionslistBox = new ListBox();
theUIPathOptionslistBox.Items.Add();
theUIPathOptionslistBox.TabIndex = nRow;
theUIPathOptionslistBox.SelectionMode = SelectionMode.Multiple;
theUIPathOptionslistBox.ClipToBounds = true;
theUIPathOptionslistBox.Focusable = true;
theUIPathOptionslistBox.Visibility = Visibility.Hidden;
theUIPathOptionslistBox.Height = 24;
I'm really hoping someone out there can help me out - it feels like I should know this but....

Assign UIPathOptionsManager.Instance.UIPathOptions to ItemSource. Performed this in Window_Loaded Event.
UIPathOptionsManager.Instance.Initialize
(#"C:\Users\Administrator\source\repos\WpfApp9");
ListBox theUIPathOptionslistBox = new ListBox();
theUIPathOptionslistBox.ItemsSource = UIPathOptionsManager.Instance.UIPathOptions;
theUIPathOptionslistBox.TabIndex = nRow;
theUIPathOptionslistBox.SelectionMode = SelectionMode.Multiple;
theUIPathOptionslistBox.ClipToBounds = true;
theUIPathOptionslistBox.Focusable = true;
theUIPathOptionslistBox.Visibility = Visibility.Hidden;
theUIPathOptionslistBox.Height = 24;
You can also do this by creating a property and then use Binding.

Related

How do I make a combobox display a list of dictionaries and act upon the selected value?

C# / Winforms program.
I have the following class which contains my dictionaries:
public class DictionaryInit
{
public Dictionary<int, DictionaryCheckup> C = new Dictionary<int, DictionaryCheckup>()
{
{1000, new DictionaryCheckup {theGrouping="C"}},
{100, new DictionaryCheckup {theGrouping="C"}},
};
}
Where DictionaryCheckup is a class that get;sets; a string theGrouping.
In the class, I would have letters from C to T, and I wanted to display their values within a combo box. This is what I've tried:
var theDictionaries = new DictionaryInit();
List<Dictionary<int, DictionaryCheckup>> Dictionaries = new List<Dictionary<int, DictionaryCheckup>> { theDictionaries.C, etc };
cmbDictionList.DataSource = new BindingSource(Dictionaries, null);
Running this fills the box with [Collection].
The process and desired outcome:
The idea is that, the user first selects a dictionary (C-T) from the combo box and the value gets saved to a variable. I then have the following code that will make use of this:
OFD.ShowDialog();
var theDict = new DictionaryInit();
if (OFD.FileName != null)
{
using (var stream = new StreamReader(File.OpenRead(OFD.FileName)))
{
// Read our JSON from the file
var json = stream.ReadToEnd();
theDict.E = JsonConvert.DeserializeObject<Dictionary<int, DictionaryCheckup>>(json);
var files = new Dictionary<string, Dictionary<int, DictionaryCheckup>>();
}
}
As you can see in my current process, I am explicitly declaring theDict.E. I wish to be able to replace it with a variable I picked up from the combo box earlier, so that I may choose which dictionary I serialize / deserialize.
I want to be able to somehow use my DictionaryInit class as the datasource of the combo box.
The value selected will determine the dictionary I will serialize in a later method.
If all DictionaryCheckup inside DictionaryInit.C have the same letter I would do it like this:
Add Letter property to DictionaryInit
Bind ComboBox to List
Set ComboBox's DisplayMember = "Letter"
Code:
public class DictionaryInit
{
public string Letter { get; private set; }
public DictionaryInit(string letter)
{
this.Letter = letter;
C = new Dictionary<int, DictionaryCheckup>()
{
{1000, new DictionaryCheckup {theGrouping=letter}},
{100, new DictionaryCheckup {theGrouping=letter}},
};
}
public Dictionary<int, DictionaryCheckup> C { get; private set; }
}
var list = new List<DictionaryInit>();
list.AddRange(new[]{new DictionaryInit("C"), new DictionaryInit("D")});
cmbDictionList.DataSource = list;
cmbDictionList.DisplayMember = "Letter";

CreateNewCheckBox with Text from XML

I'm kinda stuck with reading the value of a xml-file.
The XML looks like:
<?xml version="1.0" encoding="utf-16"?>
<spfFiles>
<file>200_006 xxxxxxx</file>
<file>200_010 xxxxxxx</file>
<file>200_022 xxxxxxx</file>
<file>200_023 xxxxxxx</file>
<file>200_024 xxxxxxx</file>
<file>200_031 xxxxxxx</file>
<file>200_041 xxxxxxx</file>
</spfFiles>
What I'm trying to do is that I want to creat a new Checkbox for each file.
XmlTextReader xReader = new XmlTextReader("spfFiles_simW.xml");
while (xReader.Read())
{
switch (xReader.NodeType)
{
case XmlNodeType.Text: //Display the text in each element.
pnlSPFLIST.Controls.Add(CreateNewCheckBox(xReader.Value));
break;
}
}
The creation of each new element works fine. But I've got trouble with the file names. Each Checkbox only gets the part before the space as a name. For example "200_006". My xmlReader somehow seems to cut the rest of.
Edit:
So here is my CreateNewCheck
private CheckBox CreateNewCheckBox(string sName)
{
label1.Text = sName;
int iExistingCheckBoxX = 0;
int iExistingCheckBoxY = 0;
int iIncrementX = 100;
int iIncrementY = 20;
CheckBox cbNew = new CheckBox();
cbNew.Width = iIncrementX;
if (pnlSPFLIST.Controls.Count == 0)
{
cbNew.Location = new Point(pnlSPFLIST.Location.X, pnlSPFLIST.Location.Y-25);
}
else
{
// Existing checkboxes, so get the Location of the last one.
iExistingCheckBoxX = pnlSPFLIST.Controls[pnlSPFLIST.Controls.Count - 1].Location.X;
iExistingCheckBoxY = pnlSPFLIST.Controls[pnlSPFLIST.Controls.Count - 1].Location.Y;
iExistingCheckBoxX = pnlSPFLIST.Location.X;
iExistingCheckBoxY = iExistingCheckBoxY + iIncrementY + 10;
cbNew.Location = new Point(iExistingCheckBoxX, iExistingCheckBoxY);
}
// Set the Text property according to the input.
cbNew.Text = sName;
return cbNew;
}
Does anyone know where I've gone wrong?
So here is the right solution.
I Just had to change my CreateNewCheckBox-Method:
private CheckBox CreateNewCheckBox(string sName)
{
...
int iIncrementX = 300;
int iIncrementY = 20;
...
}
Just increase the X-Value and everything works fine.

How do I bind a DataGridViewComboBoxColumn to the list property of the parent row's bound object?

Given the following classes:
public class Shirt
{
public string Description { get; set; }
public List<Color> ColorOptions { get; set; }
public int SelectedColorId { get; set; }
}
public class Color
{
public int Id { get; set; }
public string Label { get; set; }
}
Why can't I get the combobox to show up in the DataGridView using the following code?
List<Shirt> foundShirts = _dbShirtRepo.GetShirts();
var nameColumn = new DataGridViewTextBoxColumn();
nameColumn.DataPropertyName = "Description";
nameColumn.HeaderText = "Description";
var colorSelectColumn = new DataGridViewComboBoxColumn();
colorSelectColumn.DataPropertyName = "ColorOptions";
colorSelectColumn.DisplayMember = "Label";
colorSelectColumn.ValueMember = "Id";
dataGridView1.Columns.Add(nameColumn);
dataGridView1.Columns.Add(colorSelectColumn);
dataGridView1.DataSource = foundShirts;
Try something like this:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 1)
{
DataGridViewComboBoxCell combo = this.dataGridView1[1, e.RowIndex] as DataGridViewComboBoxCell;
combo.DataSource = ((Shirt)dataGridView1.Rows[e.RowIndex].DataBoundItem).ColorOptions;
}
}
As you can see, you have to provide DataSource per request because you can only have one at a time. There's no way to pre-set different data sources for each combo in each row.
You can improve the above solution but the concept is the same:
User clicks, hovers or otherwise "activates" the cell
Set up the DataSource of the column's combo before user has a chance to open it
This way user is not aware of any shenanigans going on and you can offer different choice for every individual row.
Note: I'm not 100% sure of how DataGridViewComboBoxCell operates, it's entirely possible that it caches and persists its data sources but experiment a bit before relying on it.
You have not set the DataSource property for the DataGridViewComboBoxColumn. There are different ways to solve your problem.
Set the DataSource of the DataGridViewComboBoxColumn to foundShirts.ColorOptions. With this you get to see only colors available in the foundShirts list.
var colorSelectColumn = new DataGridViewComboBoxColumn();
colorSelectColumn.DataPropertyName = "ColorOptions";
colorSelectColumn.DisplayMember = "Label";
colorSelectColumn.ValueMember = "Id";
colorSelectColumn.DataSource = foundShirts.ColorOptions;
If you want to see all the possible colors you could have, prepare a separate list of all possible colors and set it as the DataGridViewComboBoxColumn DataSource.
List<Color> allAvailableColorOptions = new List<Color>();
// add all the possible colors to this list.
var colorSelectColumn = new DataGridViewComboBoxColumn();
colorSelectColumn.DataPropertyName = "ColorOptions";
colorSelectColumn.DisplayMember = "Label";
colorSelectColumn.ValueMember = "Id";
colorSelectColumn.DataSource = allAvailableColorOptions;

Dynamic names for panels

I'm working on a program that is supposed to use with multiple users. I'm getting the users from a database. So far so good...
I'm dynamically adding a panel to the form, which would hold some data. I'm using this piece of code to achieve that:
string panel_name = "email_in_" + user_credentials[counter_snel][0];
Panel new_user_panel = new Panel();
new_user_panel.AutoSize = true;
new_user_panel.Dock = System.Windows.Forms.DockStyle.Fill;
new_user_panel.Location = new System.Drawing.Point(0, 0);
new_user_panel.Name = panel_name;
new_user_panel.Visible = false;
Label new_item = new Label();
new_item.AutoSize = true;
new_item.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
string new_item_text = string.Format("{0,0}\n{1,0}\n{2,0}", user_credentials[counter_snel][1], user_credentials[counter_snel][2],user_credentials[counter_snel][9]);
new_item.Text = new_item_text;
splitContainer2.panel_name.Controls.Add(new_item);
as you will probably notice, this line of code is not working:
splitContainer2.panel_name.Controls.Add(new_item);
How can I achieve this, so when I want to make panel email_in_1 visible, I can use that, and make email_in_8 not visible?
### EDIT 1 ###
the code now looks like this:
string panel_name = "email_in_" + user_credentials[counter_snel][0];
Panel new_user_panel = new Panel();
new_user_panel.AutoSize = true;
new_user_panel.Dock = System.Windows.Forms.DockStyle.Fill;
new_user_panel.Location = new System.Drawing.Point(0, 0);
new_user_panel.Name = panel_name;
new_user_panel.Visible = true;
user_email_in_panels.Add(new_user_panel);
splitContainer2.Panel1.Controls.Add(new_user_panel);
Label new_item = new Label();
new_item.AutoSize = true;
new_item.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
string new_item_text = string.Format("{0,0}\n{1,0}\n{2,0}", user_credentials[counter_snel][1], user_credentials[counter_snel][2],user_credentials[counter_snel][9]);
new_item.Text = new_item_text;
int aantal_panels = 0;
foreach (Panel panel in user_email_in_panels) {
aantal_panels++;
}
int counter_1 = 0;
foreach (Panel panel in user_email_in_panels) {
if(counter_1 == (aantal_panels -1)){
MessageBox.Show("We are here");
panel.Controls.Add(new_item);
splitContainer1.Panel1.Controls.Add(panel);
}
counter_1++;
}
But somehow, i don't see any labels shown in the form... am i missing something? The messsagebox with the text We are Here is shown, so it come's to the add statement....
and i've got an another question besides my first question. My question is, how can i make the counter of the list better?
### Edit for Sean Vaughn
i've updated it to this:
public class MyPanelClass {
public string Name {
get;
set;
}
public bool Visible {
get;
set;
}
public string YourLabelsText {
get;
set;
}
}
Label new_item = new Label();
new_item.AutoSize = true;
new_item.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
string new_item_text = string.Format("{0,0}\n{1,0}\n{2,0}", user_credentials[counter_snel][1], user_credentials[counter_snel][2], user_credentials[counter_snel][9]);
new_item.Text = new_item_text;
Panel base_panel = new Panel(); //this is your base panel, you don't need to add this line of code because Visual Studio will do that for you.
List<MyPanelClass> myPanelList = new List<MyPanelClass>(); //this will keep records of all of your panels.
MyPanelClass panel_name = new MyPanelClass();
panel_name.Name = "email_in_" + user_credentials[counter_snel][0]; ;
panel_name.Visible = true;
panel_name.YourLabelsText = string.Format("{0,0}\n{1,0}\n{2,0}", user_credentials[counter_snel][1], user_credentials[counter_snel][2], user_credentials[counter_snel][9]);
//Now add the new created panel to the list.
myPanelList.Add(panel_name);
base_panel.Name = myPanelList[counter_snel].Name;
base_panel.Visible = myPanelList[counter_snel].Visible; //You probably don't need this because base_panel will always be visible
new_item.Text = myPanelList[counter_snel].YourLabelsText;
But i still doesn't see anything...
Does it matter that it execudes in an public void??? i don't think so, but it want to elliminate all the possibilities...
Use a List that will keep track of all the panels.
List<Panel> myPanels = new List<Panel>();
Whenever you need to add a panel, do this:
mypanels.Add(yourPanel);
Now, for the other problem, create a function like this:
private void HideAllOtherPanels(List<Panel> panelList, Int index /*the index of the panel you want to show*/)
{
foreach(Panel panel in panelList)
if(panel.Visible) panel.Hide();
panelList[index].Show();
}
I see you are creating a lot of new panels. My advice, don't do that, you're giving a lot of load to the system.
Instead make a class.
public class MyPanelClass
{
public string Name
{
get; set;
}
public bool Visible
{
get; set;
}
public string YourLabelsText
{
get; set;
}
}
After creating the class, create a base_panel on your form that will change it's contents based on the your intentions.
And then, all you need to do is change the panel's content rather than creating a new Panel. Store the other panels data in a List<MyPanelClass>.
So you'll be doing this:
Panel base_panel = new Panel(); //this is your base panel, you don't need to add this line of code because Visual Studio will do that for you.
List<MyPanelClass> myPanelList = new List<MyPanelClass>(); //this will keep records of all of your panels.
MyPanelClass panel_name = new MyClassPanel();
panel_name.Name = "email_in_" + user_credentials[counter_snel][0];;
panel_name.Visible = false;
panel_name.YourLabelsText = string.Format("{0,0}\n{1,0}\n{2,0}", user_credentials[counter_snel][1], user_credentials[counter_snel][2],user_credentials[counter_snel][9]);
//Now add the new created panel to the list.
myPanelList.Add(panel_name);
Now whenever you need to activate a stored Panel, just do this:
base_panel.Name = myPanelList[yourPanelsIndex].Name;
base_panel.Visible = myPanelList[yourPanelsIndex].Visible; //You probably don't need this because base_panel will always be visible
yourLabel.Text = myPanelList[yourPanelsIndex].YourLabelsText;
This code is much less bulky on the machine and is easy to handle too.
I'd try something like this to add an item.
var panel = splitContainer2.Controls.FirstOrDefault(p => p is Panel && ((Panel)p).Name == panel_name);
if(panel != nul)
{
panel.Controls.Add(new_item);
}
To hide a particular panel given panel_name:
foreach(var control in splitContainer2.Controls)
{
if(control is Panel)
{
((Panel)control).Visible = ((Panel)control).Name == panel_name;
}
}

LINQ to XML: reading XML in C#

I am trying to read an XML file using LINQ. I have had no problem reading and parsing simple XML files but this one has me stumped.
Here is a portion of the file: The file is properly formed and valid.
<Activities>
<Activity Sport="Other">
<Id>2009-12-17T19:53:14Z</Id>
<Lap StartTime="2009-12-17T19:53:14Z">
<TotalTimeSeconds>820.5400000</TotalTimeSeconds>
<DistanceMeters>1510.3433838</DistanceMeters>
<MaximumSpeed>2.6089859</MaximumSpeed>
<Calories>104</Calories>
<AverageHeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
<Value>128</Value>
</AverageHeartRateBpm>
<MaximumHeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
<Value>139</Value>
</MaximumHeartRateBpm>
<Intensity>Active</Intensity>
<TriggerMethod>Manual</TriggerMethod>
...
and here is my code
XDocument document = XDocument.Load(myfileXml);
var query = from gtc in document.Descendants("Activities").Elements("Lap")
select new
{
Id = gtc.Parent.Element("Id").Value,
StartTime = gtc.Attribute("StartTime").Value,
TotalSeconds = gtc.Element("TotalTimeSeconds").Value,
DistanceMeters = gtc.Element("DistanceMeters").Value,
MaximumSpeed = gtc.Element("MaximumSpeed").Value,
Calories = gtc.Element("Calories").Value,
Intensity = gtc.Element("Intensity").Value,
TriggerMethod = gtc.Element("TriggerMethod").Value
};
dataGridView1.DataSource = query.ToList();
When I run this, I see the Headers in the DataGridView, but no data. Can someone please tell me where I am going wrong? Also in the solution can someone tell me how to read the value for the heart rates? Thank you!
Change Activities to Activity:
from gtc in document.Descendants("Activity").Elements("Lap")
And for the heartrate, add these two lines near the end of your select:
TriggerMethod = gtc.Element("TriggerMethod").Value,
AverageHeartRateBpm = gtc.Element("AverageHeartRateBpm").Element("Value").Value,
MaximumHeartRateBpm = gtc.Element("MaximumHeartRateBpm").Element("Value").Value
}
Here is my complete code. The only change I made apart from the two I mentioned was to remove the xsi:type attributes.
using System;
using System.Windows.Forms;
using System.Linq;
using System.Xml.Linq;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string xml = #"<Activities>
<Activity Sport=""Other"">
<Id>2009-12-17T19:53:14Z</Id>
<Lap StartTime=""2009-12-17T19:53:14Z"">
<TotalTimeSeconds>820.5400000</TotalTimeSeconds>
<DistanceMeters>1510.3433838</DistanceMeters>
<MaximumSpeed>2.6089859</MaximumSpeed>
<Calories>104</Calories>
<AverageHeartRateBpm >
<Value>128</Value>
</AverageHeartRateBpm>
<MaximumHeartRateBpm>
<Value>139</Value>
</MaximumHeartRateBpm>
<Intensity>Active</Intensity>
<TriggerMethod>Manual</TriggerMethod>
</Lap>
</Activity>
</Activities>
";
XDocument document = XDocument.Parse(xml);
var query = from gtc in document.Descendants("Activity").Elements("Lap")
select new
{
Id = gtc.Parent.Element("Id").Value,
StartTime = gtc.Attribute("StartTime").Value,
TotalSeconds = gtc.Element("TotalTimeSeconds").Value,
DistanceMeters = gtc.Element("DistanceMeters").Value,
MaximumSpeed = gtc.Element("MaximumSpeed").Value,
Calories = gtc.Element("Calories").Value,
Intensity = gtc.Element("Intensity").Value,
TriggerMethod = gtc.Element("TriggerMethod").Value,
AverageHeartRateBpm = gtc.Element("AverageHeartRateBpm").Element("Value").Value,
MaximumHeartRateBpm = gtc.Element("MaximumHeartRateBpm").Element("Value").Value
};
dataGridView1.DataSource = query.ToList();
}
}
}

Categories

Resources