I want to use listview to populate it with data and then use mouseclick event to fill some textboxes with data. I looked up an example in msdn:
ListViewItem theClickedOne = listView1.GetItemAt(e.X, e.Y);
ListViewItem theClickedtwo = listView1.FocusedItem;
if (theClickedOne != null)
{
MessageBox.Show(theClickedtwo.ToString());
//do your thing here.
//there is a reference to the listview item we clicked on
//in our theClickedOne variable.
}
but I couldn't think about a way to use it in order to differentiate the listviewitems I use since the fist Column in my program is the same and it will only give me a string with it's name(first Column).I want to have something similar to next example but for treeview.
void treeView1_NodeMouseClick(Object sender, TreeNodeMouseClickEventArgs e)
{
MessageBox.Show(e.Node.Text);
}
When populating you ListView, set the Tag property of the items, e.g.
newItem.Tag = "Item 1";
The Tag property has type object, so you can use anything you want here to identify the item. When handling the mouse click event simply check the Tag value again:
if((string)(clickedItem.Tag) == "Item 1")
{
// do stuff for this specific item.
}
Related
I am from Iran and I cant speak English very well, sorry.
I made something like OpenFileDialog in WinForms
and work correctly.
After, for better user interface, I tried to make it in WPF.
I use TreeView and other controls for it in both platforms (Winforms and WPF)
in Winforms I could do this correctly usingbelow code:
private void Folder_FileTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
{
Folder_FileTreeView.Nodes.Clear();//this is necessary to clean first page node, after get new folders
if(e.Node.Text=="Desktop")//also this code is necessary to compare node
{
//Do something
}
}
Also in WPF I can get text of Item by below code:
private void Folder_FileTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (e.NewValue!=null)
{
StackPanel CustomStackPanel = (StackPanel)((TreeViewItem)e.NewValue).Header;
TextBlock textBlock = (TextBlock)CustomStackPanel.Children[1];
nodetext = textBlock.Text;//this line return text of item for compare
}
Folder_FileTreeView.Items.Clear();
}
If I don't use Folder_FileTreeView.Items.Clear() the above code return folders without clearing first page, but if I do use Folder_FileTreeView.Items.Clear() e.NewValue returns null.
Please help me to use together these codes: Folder_FileTreeView.Items.Clear();(or clear first page) and get text of selecteditem by user without return null
Thanks A lot
e.NewItem will be null if the TreeView used to have an item selected but now does not. When you clear the items, you are removing any selection, this of course changes the selection and raises the SelectedItemChanged event with null as the new selection- since there are no possible items that could be selected.
If you want to replace the items in the list with new items after the user makes a selection, the selected item will be null while that change is happening. You need to do the following:
Handle the SelectedItemChanged event and remember the new selected item in a variable.
For example, if they click on the item for "Desktop" set a variable (e.g. Path) to the path for the user's desktop (e.g. C:\Users\UserName\Desktop).
Clear the list of folders in the TreeView. This will trigger SelectedItemChanged again, but you want to ignore it this time because e.NewItem == null.
Read all the folders in Path and make new items for each of those folders.
The way was found by below code
private void Folder_FileTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
Folder_FileTreeView.SelectedItemChanged -= Folder_FileTreeView_SelectedItemChanged;
if (e.NewValue!=null)
{
StackPanel CustomStackPanel = (StackPanel)((TreeViewItem)e.NewValue).Header;
TextBlock textBlock = (TextBlock)CustomStackPanel.Children[1];
nodetext = textBlock.Text;//this line return text of item for compare
}
Folder_FileTreeView.Items.Clear();
Folder_FileTreeView.SelectedItemChanged += Folder_FileTreeView_SelectedItemChanged;
}
thank very much for every one helped me
I have a winform with a group of comboboxes, all of the comboboxes with the same list items in them.
I need a way to confirm that when the user is done selecting a value in each box that they only selected each list value once.
Ex:
cbox1 cbox2 cbox 3
Item A Item B Item A (this needs to flag an error since Item A is already selected in cbox1)
I was thinking trying to use the selectedvaluecommited action (as after i populate the list I change the selected index to -1 so they all show "empty" to start) but the loop to make it work seems to be eluding me.
background: this is choosing fields to build a spreadsheet and the user needs to choose the field order.
You can do it like this (quick and dirty):
Add SelectedIndexChanged handler for all three comboboxes (in Form_Load in example)
comboBox1.SelectedIndexChanged += CheckComboBoxes;
comboBox2.SelectedIndexChanged += CheckComboBoxes;
comboBox3.SelectedIndexChanged += CheckComboBoxes;
in CheckComboBoxes method do your checking:
private void CheckComboBoxes(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == comboBox2.SelectedIndex ||
comboBox1.SelectedIndex == comboBox3.SelectedIndex ||
comboBox2.SelectedIndex == comboBox3.SelectedIndex)
MessageBox.Show("comboboxes are not unique");
}
EDIT:
this is approach when having n comboboxes. Put all items into list, select distinct values and compare that distinct count with items count... Something like this:
private void CheckComboBoxes(object sender, EventArgs e)
{
List<string> comboValues = new List<string>();
foreach (Control c in this.Controls)
{
if (c is ComboBox && !string.IsNullOrEmpty((c as ComboBox).SelectedItem.ToString()))
comboValues.Add((c as ComboBox).SelectedItem.ToString());
}
if (comboValues.Distinct().ToList().Count < comboValues.Count)
MessageBox.Show("not all combos are unique");
}
Here's an approach you can take.
To make the affected comboboxes easy to distinguish, put them all in a GroupBox container.
Write a validation method for your group box.
Subscribe to the group box Validating event by attaching it to your validation method.
In your validation method, loop through all the ComboBox controls in the group box and check if there are any duplicates, and issue an error if so.
For example, assuming the group box is called groupBox1:
private void GroupBox1_Validating(object sender, CancelEventArgs e)
{
base.OnValidating(e);
var selectedIndices = groupBox1.Controls.OfType<ComboBox>().Select(item => item.SelectedIndex);
var anyDuplicates = selectedIndices.GroupBy(x => x).Any(x => x.Count() > 1);
if (!anyDuplicates)
return;
MessageBox.Show("There are duplicates!");
e.Cancel = true;
}
And subscribe to the group box Validating event in the Form1 constructor:
public Form1()
{
InitializeComponent();
groupBox1.Validating += GroupBox1_Validating;
}
Sometimes when validating like this, you need to prevent the validation logic from executing if the user clicks the Cancel button. You're supposed to be able to set the CausesValidation property of the Cancel button to false to prevent this, but I find that it doesn't work for me.
Instead, I just use a bool cancelling field which I set to true in the Cancel button handler:
private void cancelButton_Click(object sender, EventArgs e)
{
cancelling = true;
this.Close();
}
bool cancelling;
And then add the following to the start of GroupBox1_Validating():
if (cancelling)
return;
If it is possible to have different UI design then my suggestion goes as under:
Alternative UI Design - A
Create One ListBox ListFieldsOriginal and populate
Create Second ListBox ListUserSelection, keep it empty initially
Provide buttons as under:
Button '>' means add currently selected item from ListFieldsOrginial to ListUserSelection at end; and remove that item from ListFieldsOriginal
Button '<' means remove currenly selected item from lstUserSelection; and add that item back to ListFieldsOriginal (of course at end)
NOTE: If adding item back to ListFieldsOriginal is your requirement then extra coding is required to find its appropriate index in the ListFieldsOriginal.
Alternative UI Design - B
Create One CheckedListBox ListFieldsOriginal and populate
Create one ListBox ListUserSelection, keep it empty initially
Define ItemCheck event handler for ListFieldsOriginal to add/remove items to/from ListUserSelected.
if (e.CurrentValue==CheckState.Unchecked)
{
string item = ListFieldsOriginal.Items[item];
ListUserSelection.Items.Add(item);
}
else
{
string item = ListFieldsOriginal.Items[item];
ListUserSelection.Items.Remove(item);
}
Suppose I have a DataGrid and a Button. CanUserAddRows is set to True. Let this dataGrid have two DataGridTextColumns namely "Name" and "Age".
Now if user takes the following actions :
He adds name as XYZ and Age as 20. Then he press enter. So a new row will be added to the datagrid.
He adds name as ABC and Age as 12. Then he press enter. So a new row will be added to the datagrid.
He keeps name empty and press Enter or TAB then I want to move focus to Button instead of next cell of datagrid.
I have watched many questions but I don't get the logic of if user left the name empty and how do I move focus to Button instead of next cell.
Use DataGridView.SelectedCells[0] so you can retrieve the value of the selected cell (assuming you can only select one).
To get the actual string inside, you will have to cast the content to a proper WPF object, like TextBlock.
myCell.Column.GetCellContent(cell.Item) as TextBlock
Then in a PreviewKeyDown event handler (KeyDown having known issues in DataGridView), you can use button.Focus(). (more about those issues)
//...
myDataGrid1.PreviewKeyDown += myDataGrid1_KeyDown;
//...
void myDataGrid1_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Enter)
{
var cell = myDataGrid1.SelectedCells[0];
TextBlock cellContent = cell.Column.GetCellContent(cell.Item) as TextBlock;
if (cellContent != null)
{
if (String.IsNullOrWhitespace(cellContent.Text))
button.Focus();
}
}
}
About getting the column's name, it's another question, for which you can find answer here for example.
As a side note, you're not really supposed to interact directly with a DataGridView cells' values, since it's meant to be bound with a data source from which you should retrieve the data you want to test. However, you can search a bit for helper methods that can help you get what you want.
You can define a handler for the DataGrid.KeyDown event, as:
void myDataGrid1_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Enter)
{
button.Focus();
}
}
In my C# WPF application (.NET 4.0) I have a DataGrid dynamically filled from code including a DataGridComboBoxColumn:
public static DataGridComboBoxColumn getCboCol(string colName, Binding textBinding)
{
List<string> statusItemsList = new StatusList();
DataGridComboBoxColumn cboColumn = new DataGridComboBoxColumn();
cboColumn.Header = colName;
cboColumn.SelectedItemBinding = textBinding;
cboColumn.ItemsSource = statusItemsList;
return cboColumn;
}
Using the BeginningEdit event different checks are performed.
If the checks return okay, I want to expand the combobox directly, otherwise edit mode is cancelled:
void dataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
...
if(notOK)
e.Cancel;
else {
DataGridComboBoxColumn dgCboCol = (DataGridComboBoxColumn)e.Column;
// expand dgCboCol
}
...
}
Questions: How to expand the combobox programmatically? Is BeginningEdit event the right place to do that?
Answer:
void dataGrid_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
{
if (e.EditingElement.GetType().Equals(typeof(ComboBox)))
{
ComboBox box = (ComboBox)e.EditingElement;
box.IsDropDownOpen = true;
}
}
Take a look at this
Try setting edit mode on the grid to a single click and then use the CellClick event to obtain the comboBox and expand it.
dataGrid.BeginEdit(true);
ComboBox comboBox = (ComboBox)dataGrid.EditingControl;
comboBox.IsDropDownOpen = true;
From DataGridBeginningEditEventArgs, you could access the generated element for the cell about to be edited like this:
var contentComboBox = e.Column.GetCellContent(e.Row) as ComboBox;
However, I'm not sure that this will get the actual ComboBox you need. DataGrids can generate two different elements for each cell, depending on whether they are in edit mode (read-only and read-write elements). Since BeginningEdit happens just before entering edit mode, this will get the read-only element.
The better event to handle this in would probably be PreparingCellForEdit, which will fire after BeginEdit is actually called on the data item (in other words, if BeginningEdit was not canceled). In that event, you can access the element directly through the EditingElement property.
I want to select item in a ListView upon clicking. I also want to know what I clicked.
I work on winforms with c#.I also want to know How I can clicking the all row?
Just handle the Click event on the list and use the ListView.SelectedItems property to get what items are selected:
private void listView1_Click(object sender, EventArgs e)
{
var firstSelectedItem = listView1.SelectedItems[0];
}
u can use MouseEventArgs and get the mouse location check if it exists inside the selected item bound , that means the click was made on the selected item .
EDIT :
example :
private void myList_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (myList.SelectedItems.Count >= 1)
{
ListViewItem item = myList.SelectedItems[0];
//here i check for the Mouse pointer location on click if its contained
// in the actual selected item's bounds or not .
// cuz i ran into a problem with the ui once because of that ..
if (item.Bounds.Contains(e.Location))
{
MessageBox.Show("Double Clicked on :"+item.Text);
}
}
}
also if you use xaml for window then you must add MouseUp="listView1_Click" attribute to ListView tag