I have a listview control in my windows application, which is populated with some set of items. I will make the selection of an item programmatically by setting ListViewItem.Selected property to true. But I want to prevent the user from selecting an item in the listview. i.e., it should be always selected programmatically. I can prevent the user selection by disabling the control, but disabling the control will also disable the scroll bars which is not correct.
Even I have created a custom listview control and implemented a ItemSelectionChanging eventhandler using WndProc check link, using which i can cancel the event as shown below,
private void lstLiveTables_ItemSelectionChanging(object sender, ListViewExItemSelectionChangingEventArgs e)
{
e.Cancel = true;
}
But again, this will cancel the event, even for an item selected programmatically. My question, is there anyway to identify whether the selection is made manually (by user) or programmatically in SelectedIndexChanged or using WndProc Message.
Note: If it is required, I will upload the code of CustomListView control.
Update 1
Thanks emartel. It was a good thought. Even I tried to achieve the same thing by subscribing to the event only before selecting the item and removed it immediately after selecting. By this way, upon selection the event will be immediately triggered and it will continue. This is working fine.
this.lstTables.SelectedIndexChanged += new System.EventHandler(this.lstTables_SelectedIndexChanged);
item.Selected = true;
this.lstTables.SelectedIndexChanged -= new System.EventHandler(this.lstTables_SelectedIndexChanged);
But again I have a problem that, if the user selects an item manually, nothing will happen (no event will be triggered) but the item alone will be highlighted. Once an item is highlighted and if i try to select the same item programmatically nothing is happening i.e., the SelectedIndexChanged event is not getting triggered for that item as it is already highlighted.
Note: Same behavior even if I follow the Flag approach suggested by you.
Update 2
I can solve this issue by having my own method instead of handling through events as emartel's suggestion. But my question is, according to my update 1, is there anyway to trigger the SelectedIndexChanged event when the item is highlighted but not actually selected?
public FrmTest()
{
list.ItemSelectionChanged += list_ItemSelectionChanged;
}
private bool changing;
private void list_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
if (changing)
return;
if (e.Item == nonSelectableListItem)
{
changing = true;
nonSelectableListItem.Selected = false;
changing = false;
}
}
Sample:
Well, an easy solution would be to keep a flag saying that you are programmatically changing the selection and to allow the event to pass, and reset the flag when you're done
Edit: if you, and only you, can change the selection, and you do this programmatically, so you have control over where and when this happens, why do you even need the EventHandler? Why not call a method to do whatever processing you want to happen?
One dirty way to do that is to keep list of selected items and refresh selection every time it changes other way than from your code.
There is also an ItemSelectionChanged event which is raised separately for every item whose selection state have changed. You can probably flip the selection state back it this event.
You may also take a look on Better ListView Express control. It have a read-only mode, so that user cannot change the selection. Its setup is very simple:
listView.ReadOnly = true;
The full version also supports custom non-selectable items. Simply setting:
listView.Items[0].Selectable = false;
make the first non-selectable (by the user).
You can still select items from code, of course.
The following image shows non-selectable items in action (they are marked by gray color):
Related
I have this Repository Item comboboxEdit in a Devexpress CustomGridView.
private void gridView1_CustomRowCellEditForEditing(object sender, DevExpress.XtraGrid.Views.Grid.CustomRowCellEditEventArgs e)
{
if (e.Column == this.gcCol1)
{
var repositoryItem = new RepositoryItemComboBox();
foreach (var title in this.ViewModelList.Titles)
{
repositoryItem.Items.Add(title.TitleName);
}
repositoryItem.EditValueChanged += this.PostEditValueChanged;
repositoryItem.Validating+=this.validating;
e.RepositoryItem = repositoryItem;
}
}
private void PostEditValueChanged(object sender, EventArgs e)
{
this.gridView1.PostEditor();
}
EditValueChanged fires many times while typing. Is there a way to fire this EditValueChanged once after the user has completely finished editing the cell.
Something along these lines http://www.devexpress.com/Support/Center/Question/Details/Q288616
Devexpress Support had some fix for this problem but didn't seem to help.
Not sure why the activeedior is closing and resetting the cursor.
I don't want to be setting the caret position in EditValueChanged.
I also tried CellvalueChanged but this would require a click in the usercontrol.
Same with repository.validating
repositoryItem.EditValueChanged += this.PostEditValueChanged;
repositoryItem.Validating+=this.validating;
Is there a way to figure out if the user is done or still editing the combox box and then fire the editvaluechanged without having to worrying out clicks outside the combo box edit
A better approach:
Handle the GridView's CellValueChanged event, rather than EditValueChanged on the editor.
In the handler, determine which column fired the event. For example,
if (e.Column.Equals(this.gvColTitle))
{
//Access the repository item:
ComboBoxEdit editor = this.gridView1.ActiveEditor as ComboBoxEdit;
//Assign your values to the editor.
}
I'm not sure why you're adding the repository item at runtime, but you may be able to just create it in the XtraGrid Designer screen, and assign it to the column there. You can still update its item list at runtime using the above.
I was able to resolve this issue by not firing the EditvalueChanged and using the Validating event.
This event fires when the editor is about to lose focus. Its unlike CellvalueChanged where if the user clicks on the form and not on the usercontrol, the change is lost.
gridView1.PostEditor(); will show the editor after populating the values. Similarly, We can change the validating event to fire on 'Enter Key' to resolve as a quick fix.
I have a treeview with a list of items that are expandable. When the user checks the checkbox for a parent node, I simulate checking the children nodes. However, the user can check any node (not just parent nodes). I want to distinguish the user's first click, which triggers the node's checkbox event, from the simulated checking of the children node's checkboxes.
I want to distinguish the User's click so I can save the state of the treeview before it changes.
I thought of using a mousedown event, but this doesn't work since the user might click to expand something and I do not want to save the state of the treeview since nothing changed. One way to make this work would be to calculate the dimensions of each checkbox location and then check the mousedown's click coordinates, but I would like to avoid doing this as it would not be easy since I have nested nodes so the check boxes have a few different columns they could be.
Another way to think of this is I want to turn groups of events into actions. So one action would represent the User's first action, and all the simulated actions that followed until control is returned to the user.
Another thought, maybe I could do something with window focusing or control. For instance if the window is not focused while simulating, I could just save on the focus change if it would occur during a User's action of checking a tree node's checkbox.
Additional info
The simulated checkbox clicks are invoked by code such as:
e.Node.Checked = false;
This triggers the event:
private void tree_AfterCheck(object sender, System.Windows.Forms.TreeViewEventArgs e)
When a user clicks a node, this AfterCheck event triggers. I want to save the state of the tree here. But inside the AfterCheck event, there are cases that check other nodes causing the AfterCheck event to trigger again n times, but this time the check for the checkbox was simulated.
Systems.Windows.Forms.TreeView is the sender object in all cases.
Have you tried the CheckBox.Click event?
This would make it easy to tell that the user was clicking to make the change.
You could also use a flag to indicate that any events raised would be because the method was making the change. Since this is a windows form, the user will not be able to check another box until your process has finished (so there is no raceway condition).
/// <summary>
/// Flag which can be accessed by the checkboxes which indicates if the program is making the change or the user is.
/// </summary>
bool programmaticallySettingChecks { get; set; }
protected void FlagExample()
{
CheckBox[] chToCheck = new CheckBox[10]; //Collection of checkboxes to set the Checked property on.
programmaticallySettingChecks = true;
for (int i = 0; i < chToCheck.Length; i++)
{
chToCheck[0].Checked = true;
}
programmaticallySettingChecks = false;
}
protected void Check_Clicked(Object sender, EventArgs e)
{
if (programmaticallySettingChecks)
{
//do things which are done if setting programmatically.
}
else
{
//Do things which are done if user sets.
}
}
Can you provide us with some code that you've tried?
If the user will only click parent nodes and you will only select child nodes, then perhaps you can do a simple check during the event trigger that says "If parent node, then execute, otherwise return"
I'm working on an async binding control that inherits a ComboBox (and a Textbox in other scenarios, but that's not really relevant..). I've replaced a bunch of existing ComboBoxes on the forms in this application, which for most of these controls has worked perfectly. Except for one...
My box overrides the OnSelectedIndexChanged method with the following code:
protected override void OnSelectedIndexChanged(EventArgs e)
{
if (!Helper.ItemsApplied)
return; //don't worry! the index will be selected when the items are applied!
_selectedValue = Helper.GetValue(Text);
base.OnSelectedIndexChanged(e);
}
This works fine, until someone tries to handle the value change using the SelectionChangeCommitted event. Perfectly within reason though; I shouldn't be changing their code to use the SelectedIndexChanged, because this functionality shouldn't execute when the value is programmatically invoked (see the MSDN Article).
However, my functionality does need to be executed when the index is programmatically changed, but it needs to execute before the SelectionChangeCommitted event does! The SelectionChangeCommitted event is fired before the SelectedIndexChanged event.
Any ideas on how I could get round this? Preferably only by changing the code in my control and not in their form?
I want to disable selecting text and clicking in the middle of text in a TextBox, but the user must be able to enter this TextBox and write at the end of earlier text, so I cannot make it ReadOnly or Enable = false.
I try to handle MouseDown and do the following:
input.Select(input.Text.Length, 0);
It helps with placing a cursor in the middle of text, but the user still can make a selection from the end.
I also make a MessageBox() on MouseDown event, but in this case the user cannot click on textBox and write anything.
The last try was to set a focus() in another Control and focus back, after a period of time, but it didn't work at all. User still can make a selection.
How can I do it?
How about this for Click event
Edit: Also do the same for DoubleClick and MouseLeave to cover all cases. You can have a common event handler.
private void textBox1_Click(object sender, EventArgs e)
{
((TextBox) sender).SelectionLength = 0;
}
If it fits the UI/user model, another approach is to use two text boxes: a read-only one with the previous text that the user can see and act on (if that is something he needs to do) and an editable one for the new text along with a button to commit the new text to the read-only text box (and persistence layer).
That approach is not only arguably more user-friendly—the editable box is completely editable rather than just "appendable", which gets confusing when the user hits Backspace—but also requires less fighting with the framework to make the boxes do what you need.
You're not far off with your MouseDown event handler, but probably better to catch MouseUp, as this is the event that will fire when they have finished selecting.
Alternatively, you could catch the SelectionChanged event.
Just put your:
input.Select(input.Text.Length, 0);
code in any of those event handlers.
How to detect what specific cell was clicked in DataGrid?
I'm pretty sure you're looking for the selectedindexchanged event
Did you try to handle CellClik or CellContentClick events?
Suppose I haven't found this answer as well, (To determine a cell click).
And suppose I wanted to use it to be able to check/uncheck a checkbox, upon first click.
Then I guess the designer of this library would not approve of doing, it the following way, (I can (de)select my checkbox this way, but it seems unwise/dangerous as your changing the selected item property of the grid.)
So what we need is someone telling us how we can detect a cell's click otherwise some of us
may want to use the selectionchanged event, the bad thing about this is that you lose info on
which row of the grid pass pressed.
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (dataGridInstance.SelectedItem != null)
{
//do what you need to do with the data. (for example start with:)
Microsoft.Windows.Controls.DataGridCellInfo datagridCellInfo = dataGridInstance.CurrentCell;
//when you are done, set selectiTem to null, so even upon a next click on the same
//cell this method will be called again
dataGridTeam.SelectedItem = null;
}
}