How to access a class from a listbox item? - c#

I build a class that stores values from an XML file. I am loading that data into a ListBox like this:
private void LoadBookXML(string bookXML, ListBox theBookListBox)
{
XDocument loadedData = XDocument.Load(bookXML);
var data = from query in loadedData.Descendants("book")
select new Books
{
Title = (string)query.Attribute("title").Value.ToUpper(),
Theme = (string)query.Attribute("theme").Value,
Abbreviation = (string)query.Attribute("abbr").Value,
Chapters = (string)query.Attribute("chapters").Value,
Writer = (string)query.Attribute("writer").Value,
Place = (string)query.Attribute("place").Value,
Completed = (string)query.Attribute("completed").Value,
Time = (string)query.Attribute("time").Value,
Summary = (string)query.Attribute("summary").Value,
Link = (string)query.Attribute("link").Value,
Number = (string)query.Attribute("number").Value,
WriterAndPlace = "Written by " + (string)query.Attribute("writer").Value + " in " + (string)query.Attribute("place").Value,
};
theBookListBox.ItemsSource = data;
GestureService.GetGestureListener(theBookListBox).Hold += new EventHandler<GestureEventArgs>(theBookListBox_Hold);
When I press and hold an item in the ListBox, I am calling a function that brings up context menu like this:
private void theBookListBox_Hold(object sender, GestureEventArgs e)
{
AppState state = ThisApp._appState;
if (e.OriginalSource is TextBlock)
{
if (((string)((e.OriginalSource as TextBlock).Name)) == "btBookName")
{
UpdateLayout();
_cmReader = new ContextMenu();
MenuItem item = new MenuItem();
item.IsEnabled = true;
item.IsHitTestVisible = true;
TextBlock block = new TextBlock();
block.Text = "HELP, I AM TRYING TO GET DATA FROM THE BOOKS CLASS!!!";
block.TextDecorations = TextDecorations.Underline;
item.Header = block;
MenuItem item5 = new MenuItem
{
Header = "book info"
};
item5.Click += new RoutedEventHandler(bookInfo_Click);
_cmReader.Items.Add(item);
_cmReader.Items.Add(item5);
OpenContextMenu();
}
}
}
So my question is how can I access the data from the Books class that is stored into each of the ListBoxItems? I am using C#.

is that what you mean?
Books book = theBookListBox.SelectedItem as Books;
//All
foreach(Books book in theBookListBox.Items)
{
}

I think your class is inside of the form.
So its better do this...
private void LoadBookXML()
{
string bookXmL = "";
listBox theBookListBox = new ListBox();
Your other code here..
}
then.....
private void theBookListBox_Hold(object sender, GestureEventArgs e)
{
AppState state = ThisApp._appState;
if (e.OriginalSource is TextBlock)
{
if (((string)((e.OriginalSource as TextBlock).Name)) == "btBookName")
{
LoadBookXML();
Your other code here...
}
}
}

Related

Creating a Listview filter in WPF with a text box search

I am creating an application with an XML file called star.xml to store my data in a list view. I am very new to c# and programming and need any help
Basically, I want to be able to type in my search text box (called 'search') and for my list view (lstStar) to only show the matching records. I.e. typing in 'Audi' will only return those items.
any help will be much appreciated
jen
namespace StarinCar
{
public partial class MainWindow : Window
{
int hot = -2;
int Mildly_Moist = -2;
int Wet = -4;
int Very_Wet = -6;
private ObservableCollection<star> starData;
public MainWindow()
{
InitializeComponent();
starData = new ObservableCollection<star>();
lstStar.ItemsSource = starData;
try
{
XmlSerializer xs = new XmlSerializer(typeof(ObservableCollection<star>));
using (StreamReader rd = new StreamReader("star.xml"))
{
starData = xs.Deserialize(rd) as ObservableCollection<star>;
}
}
catch
{
}
lstStar.ItemsSource = starData;
lblAverage.Content = starData.Average(i => i.time).ToString();
lblFastest.Content = starData.Min(i => i.time).ToString();
lblSlowest.Content = starData.Max(i => i.time).ToString();
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
star newStar = new star();
newStar.firstName = txtName.Text;
newStar.time = int.Parse(txtTime.Text);
newStar.car = txtCar.Text;
newStar.track = txtTrack.Text;
starData.Add(newStar);
if (txtTrack.Text.Contains("Hot") || (txtTrack.Text.Contains("hot") == true))
{
newStar.time = int.Parse(txtTime.Text) + hot;
}
if (txtTrack.Text.Contains("Mildly Moist") || (txtTrack.Text.Contains("mildly moist")) == true)
{
newStar.time = int.Parse(txtTime.Text) + Mildly_Moist;
}
if (txtTrack.Text.Contains("Wet") || (txtTrack.Text.Contains("wet") == true))
{
newStar.time = int.Parse(txtTime.Text) + Wet;
}
if (txtTrack.Text.Contains("Very Wet") || (txtTrack.Text.Contains("very wet")) == true)
{
newStar.time = int.Parse(txtTime.Text) + Very_Wet;
}
}
private void Window_Closed(object sender, EventArgs e)
{
XmlSerializer xs = new XmlSerializer(typeof(ObservableCollection<star>));
using (StreamWriter wr = new StreamWriter("star.xml"))
{
xs.Serialize(wr, starData);
}
}
}
}
You could use ICollectionView. So you would have your "overall"
star collection 'starData'. But your listbox itemssource would be bound to something like this:
public ICollectionView FilteredStars
{
get
{
ICollectionView source = CollectionViewSource.GetDefaultView(starData);
source.Filter = new Predicate<object>(FilterStars);
return source;
}
}
the logic that does the filtering here:
private bool FilterStars(object item)
{
bool b = false;
star a = item as star;
if (a != null)
{
if (a.Name.Contains(searchBoxText)) //your filter logic here
{
b = true;
}
else if String.IsNullOrWhiteSpace(searchBoxText)
{
b = true;
}
}
return b;
}
Basically, you have your main collection, then some logic that filters your main collection to a filtered collection, and that's what you should set itemssource of your listbox to. This, so far, is assuming you are going to put some kind of property change into your search text box and probably then click a button, like "Search" to then tell the list to check and re-populate to match the search term.
This is how I filter in a similar application
public IEnumerable<string> PastEntries1
{
get
{
if(string.IsNullOrEmpty(textValue))
{
return FieldDefString.PastEntries;
}
else
{
return FieldDefString.PastEntries.Where(x => x.StartsWith(textValue, StringComparison.OrdinalIgnoreCase));
}
}
}

Add items to DataGridView

I have a grid in which the sizes must be at the same height from the description.
private void btnAgregar_Click(object sender, EventArgs e)
{
dgvProformaDetalle.AutoGenerateColumns = false;
dgvProformaDetalle.DataSource = FillDgv();
dgvProformaDetalle.Columns["ColumnId"].DataPropertyName = "ProductoId";
dgvProformaDetalle.Columns["ColumnDescripcion"].DataPropertyName = "DescripcionProducto";
dgvProformaDetalle.Columns["ColumnTalla"].DataPropertyName = "DescripcionTalla";
}
private List<DetalleProformaExtendida> FillDgv()
{
List<DetalleProformaExtendida> listaArticulo = new List<DetalleProformaExtendida>();
DetalleProformaExtendida model = new DetalleProformaExtendida
{
ProductoId = txtIdProducto.Text,
DescripcionProducto = txtDescripcion.Text
};
listaArticulo.Add(model);
foreach (Talla item in checkedListBoxTallas.CheckedItems)
{
DetalleProformaExtendida _talla = new DetalleProformaExtendida();
_talla.TallaId = item.TallaId;
_talla.DescripcionTalla = item.Descripcion;
listaArticulo.Add(_talla);
}
return listaArticulo;
}
Maybe you want to set the ContentAlignment of your Cells? Maybe to TopLeft or TopRight?
dgvProformaDetalle.Columns["ColumnDescripcion"].CellTemplate.Style.Alignment =
DataGridViewContentAlignment.TopLeft;
dgvProformaDetalle.Columns["ColumnTalla"].CellTemplate.Style.Alignment =
DataGridViewContentAlignment.TopRight;
But I am really just guessing here..

ListView selected item to TextBox

First, I have filled a list object with the data from xml file. After that, I have filled a ListView with the necessary fields, without any problem. How can I get the index from the selected ListView item and then give appropriate value to some textbox?
This is the code for it:
private void Form1_Load(object sender, EventArgs e)
{
List<Tasks> taskList = new List<Tasks>();
listView1.Columns.Add("Date:");
listView1.Columns.Add("Job:");
listView1.Columns.Add("Client Name");
listView1.Columns.Add("Submitted by");
taskList = getTasks();
listView1.Items.Clear();
for (int i = 0; i < taskList.Count; i++)
{
Tasks task = taskList.ElementAt(i);
ListViewItem row = new ListViewItem();
row.Text=task.date.ToString();
row.SubItems.Add(task.job);
row.SubItems.Add(task.clientName);
row.SubItems.Add(task.submittedBy);
listView1.Items.Add(row);
}
}
public List<Tasks> getTasks()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("data.xml");
XmlNodeList nodes = xmlDoc.DocumentElement.SelectNodes("/tasks/task");
List<Tasks> taskList = new List<Tasks>();
foreach (XmlNode node in nodes)
{
Tasks task = new Tasks();
task.id = Convert.ToInt32(node.SelectSingleNode("id").InnerText);
task.date = Convert.ToDateTime(node.SelectSingleNode("submittedDate").InnerText);
task.submittedBy = node.SelectSingleNode("submittedBy").InnerText;
task.clientName = node.SelectSingleNode("clientName").InnerText;
task.job = node.SelectSingleNode("job").InnerText;
task.taskCategory = node.SelectSingleNode("taskCategory").InnerText;
task.taskDescription = node.SelectSingleNode("taskDescription").InnerText;
task.hours = node.SelectSingleNode("hours").InnerText;
task.status = node.SelectSingleNode("status").InnerText;
task.isBilled = node.SelectSingleNode("isBilled").InnerText;
task.cost = node.SelectSingleNode("cost").InnerText;
task.followUpInfo = node.SelectSingleNode("followUpInfo").InnerText;
task.invoiceNumber = node.SelectSingleNode("quickBooksInvoiceNo").InnerText;
taskList.Add(task);
}
return taskList;
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
}
What I need is now how when I click an item from the listView1 to show some value in a textbox? But that value should be taken from the list object taskList, not from the xml document itself.
Store your task ID inside of your item's Tag property:
row.Tag = task.id;
Then handle ListView.SelectedIndexChanged event
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
var id = (int) listView1.SelectedItems[0].Tag;
var currenTask = taskList.Where(t => t.id == id).First();
textBox1.Text = currenTask.taskDescription; // for example
}
}
Also you should define your taskList in the class level, outside of your Form_Load method.Otherwise you can't access it from SelectedIndexChanged event.
List<Tasks> taskList = new List<Tasks>();
private void Form1_Load(object sender, EventArgs e)
{
...
}

How to: Get information from dynamic data

This might sound strange at first but its rather simple. I have a wcf webservice (restful) in this service I have set some generic "user" fields and one of the fields which I have set is the userID to increment every time a user is added. All pretty simple stuff.
I then have a consuming wpf application. For each of the users mentioned above in my webservice I dynamically set out content to hold each of those users in my wpf application which is done on button click, this then loads the content area with groupboxs and textblocks neatly arranged (again pretty simple). The containers I hold them in are GroupBox.Header which holds the userID and Textblock which equals the students first name and last name.
Like so:
private void button1_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(textBox1.Text))
{
PanelMainContent.Children.Clear();
MainArea1.Children.Clear();
string uriGroups = "http://localhost:8000/Service/Student";
XDocument xDoc = XDocument.Load(uriGroups);
var sortedXdoc = xDoc.Descendants("Student")
.OrderByDescending(x => Convert.ToDateTime(x.Element("TimeAdded").Value));
foreach (var node in xDoc.Descendants("Student").OrderByDescending(x => Convert.ToDateTime(x.Element("TimeAdded").Value)))
{
GroupBox groupbox = new GroupBox();
groupbox.Header = String.Format(node.Element("StudentID").Value);
App.Current.Properties["groupboxHeader"] = groupbox.Header;
groupbox.Width = 100;
groupbox.Height = 100;
groupbox.Margin = new Thickness(1);
Button btnFindStudent = new Button();
btnFindStudent.Click += this.btnGeneral_Click;
btnFindStudent.Name = Convert.ToString("btnViewStudent");
btnFindStudent.Tag = Convert.ToString("ViewStudent");
btnFindStudent.Content = Convert.ToString("View");
btnFindStudent.HorizontalAlignment = HorizontalAlignment.Right;
btnFindStudent.Height = 20;
btnFindStudent.Width = 36;
TextBlock textBlock = new TextBlock();
textBlock.Text = String.Format(node.Element("FirstName").Value + " " + (node.Element("LastName").Value));
textBlock.TextAlignment = TextAlignment.Center;
TextBlock textBlock1 = new TextBlock();
textBlock1.Text = (DateTime.Parse(node.Element("TimeAdded").Value)).ToString("d");
String.Format("{0:d/M/yyyy}", DateTime.Parse(node.Element("TimeAdded").Value));
textBlock1.TextAlignment = TextAlignment.Center;
textBlock1.VerticalAlignment = VerticalAlignment.Bottom;
StackPanel stackPanel = new StackPanel();
stackPanel.Children.Add(groupbox);
stackPanel.Children.Add(btnFindStudent);
stackPanel.Children.Add(textBlock);
stackPanel.Children.Add(textBlock1);
stackPanel.Margin = new Thickness(5);
stackPanel.MouseEnter += new MouseEventHandler(stackpanel_MouseEnter);
stackPanel.MouseLeave += new MouseEventHandler(stackpanel_MouseLeave);
MainArea1.Children.Add(stackPanel);
}
}
And the output looks like this:
Notice the GroupBox.header states the UserID.
So this brings me to the problem... if you notice in the image I also dynamically set a button (code above). This button loads a usercontrol applie named ThisUser :) but the problem I am having is being able to:
1) First get GroupBox.Header(UserID) of the currently clicked
student (SOLVED by Darins answer below)
2) Send that UserID to the usercontrol "ThisUser"
To explain question 1):
Looking at the code above is there a way in which I can "Get" the groubox.header of that user who has been clicked ("view" button in the image of my app)
And for question 2)
Somehow "send" from my current app to the usercontrol "ThisUser" or "make available" for the usercontrol to then consume.
I hope this has been nice and clear and layed out well to provide the best possible answer, if there is anything else you wish to know (code, explanation) please dont hesitate to ask.
Code to send data on btnGeneralClick (view button):
public FindStudent()
{
InitializeComponent();
}
private void btnGeneral_Click(object sender, RoutedEventArgs e)
{
ViewStudent myusercontrol = new ViewStudent();
String id = (String)((Button)sender).Tag;
myusercontrol.StudentID = id;
PanelMainContent.Children.Add(myusercontrol);
}
UserControl:
public partial class ViewStudent : UserControl
{
public ViewStudent()
{
InitializeComponent();
}
private string _studentID;
public string StudentID
{
get
{
return _studentID;
}
set
{
_studentID = value;
}
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
groupBox1.Header = StudentID;
//or
textBlock1.Text = StudentID;
}
}
Well, first, I'd put the StudentID in the btnFindStudent.Tag
btnFindStudent.Tag = node.Element("StudentID").Value.ToString();
When the ClickEvent is fired, you can pull the ID out of the Tag and send it off to your ThisUser UserControl.
String id = (String)((Button)sender).Tag;
I'd just create a public property in the UserControl called "StudentID" and set it there. It's hard to say without seeing your UserControl. :(
More Information:
Add this to ViewStudent:
#region StudentID
public static readonly DependencyProperty StudentIDProperty = DependencyProperty.Register("StudentID", typeof(String), typeof(ViewStudent), new PropertyMetadata(OnStudentIDChanged));
public string StudentID
{
get { return (string)GetValue(StudentIDProperty); }
set { SetValue(StudentIDProperty, value); }
}
static void OnStudentIDChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as ViewStudent).OnStudentIDChanged(e);
}
void OnStudentIDChanged(DependencyPropertyChangedEventArgs e)
{
groupBox1.Header = StudentID;
textBlock1.Text = StudentID;
}
#endregion
And get rid of that other StudentID Property we made earlier.
ViewStudent myUserControl = new ViewStudent();
myUserControl.StudentID = (String)((Button)sender).Tag;
Give that a shot. (:

Opening a ContextMenu from a ToolStripMenuItem

I am trying to mimic the behavior of, for example, Windows Explorer and how the Favorites items can launch a context menu.
I currently am using:
contextMenu.Show((sender as ToolStripMenuItem).GetCurrentParent().PointToScreen(e.Location));
This occurs in the MouseDown event of the ToolStripMenuItem. The problem is that the menu closes immediately after right-click, and I don't know any way to suspend it while the context menu is open.
I've tried deriving from ToolStripMenuItem and overriding the MouseDown/MouseUp but I can't figure out how to keep it open on click.
Is there a good way of doing this?
This is what I've had luck with, it's a bit more direct:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
void MenuItemContext(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) return;
ToolStripMenuItem mID = (ToolStripMenuItem)sender;
ContextMenu tsmiContext = new ContextMenu();
MenuItem Item1 = new MenuItem();
MenuItem Item2 = new MenuItem();
Item1.Text = "Item1";
Item2.Text = "Item2";
tsmiContext.MenuItems.Add(Item1);
tsmiContext.MenuItems.Add(Item2);
Item1.Click += new EventHandler(Item1_Click);
Item2.Click += new EventHandler(Item2_Click);
hndPass = mID.Text;
tsmiContext.Show(menuStrip1, menuStrip1.PointToClient(new Point(Cursor.Position.X, Cursor.Position.Y)));
}
private String hndPass;
void Item1_Click(object sender, EventArgs e)
{
MenuItem mID = (MenuItem)sender;
MessageBox.Show("You clicked " + mID.Text + " in the context menu of " + hndPass);
}
void Item2_Click(object sender, EventArgs e)
{
MenuItem mID = (MenuItem)sender;
MessageBox.Show("You clicked " + mID.Text + " in the context menu of " + hndPass); ;
}
}
One way that you could accomplish this is by using the ToolStripDropDown control to host a ListBox inside of the ToolStripDropDown.
This may require some tweaking regarding the AutoClose behavior, but it should get you started:
First in your main form, add the following line to your ToolStripDropDropDown item
toolStripDropDownButton1.DropDown = new CustomListDropDown();
Then create a custom drop down class as follows:
public class CustomListDropDown : ToolStripDropDown
{
private ContextMenuStrip contextMenuStrip1;
private ToolStripMenuItem toolStripMenuItem1;
private ToolStripMenuItem toolStripMenuItem2;
private ToolStripMenuItem toolStripMenuItem3;
private System.ComponentModel.IContainer components;
public ListBox ListBox { get; private set; }
public CustomListDropDown()
{
InitializeComponent();
this.ListBox = new ListBox() { Width = 200, Height = 600 };
this.Items.Add(new ToolStripControlHost(this.ListBox));
this.ListBox.ContextMenuStrip = contextMenuStrip1;
this.ListBox.MouseDown += new MouseEventHandler(ListBox_MouseDown);
contextMenuStrip1.Closing += new ToolStripDropDownClosingEventHandler(contextMenuStrip1_Closing);
//add sample items
this.ListBox.Items.Add("Item1");
this.ListBox.Items.Add("Item2");
this.ListBox.Items.Add("Item3");
this.ListBox.Items.Add("Item4");
}
void contextMenuStrip1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
this.Close();
this.AutoClose = true;
}
void ListBox_MouseDown(object sender, MouseEventArgs e)
{
this.AutoClose = false;
this.ListBox.SelectedIndex = this.ListBox.IndexFromPoint(e.Location);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem();
this.contextMenuStrip1.SuspendLayout();
this.SuspendLayout();
//
// contextMenuStrip1
//
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripMenuItem1,
this.toolStripMenuItem2,
this.toolStripMenuItem3});
this.contextMenuStrip1.Name = "contextMenuStrip1";
//
// contextMenuStrip1.ContextMenuStrip
//
this.contextMenuStrip1.Size = new System.Drawing.Size(181, 48);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(180, 22);
this.toolStripMenuItem1.Text = "toolStripMenuItem1";
//
// toolStripMenuItem2
//
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
this.toolStripMenuItem2.Size = new System.Drawing.Size(180, 22);
this.toolStripMenuItem2.Text = "toolStripMenuItem2";
//
// toolStripMenuItem3
//
this.toolStripMenuItem3.Name = "toolStripMenuItem3";
this.toolStripMenuItem3.Size = new System.Drawing.Size(180, 22);
this.toolStripMenuItem3.Text = "toolStripMenuItem3";
//
// CustomListDropDown
//
this.Size = new System.Drawing.Size(2, 4);
this.contextMenuStrip1.ResumeLayout(false);
this.ResumeLayout(false);
}
}
In my tests this worked reasonably well. Let me know how it goes.
As ContextMenuStrip is derived from ToolStripDropDown, you could do this:
private ContextMenuStrip CopyToContextMenu(ToolStripMenuItem mnuItemSource)
{
var mnuContextDestination = new ContextMenuStrip();
//Move itens from ToolStripMenuItem to ContextMenuStrip
while (mnuItemSource.DropDown.Items.Count > 0)
{
mnuContextDestination.Items.Add(mnuItemSource.DropDown.Items[0]);
}
//Put ContextMenuStrip in ToolStripMenuItem using DropDown property
mnuItemSource.DropDown = mnuContextDestination;
return mnuContextDestination;
}

Categories

Resources