How to stop a bindingSouce/ComboBox from changing selection - c#

I have a simple form with list as a data source, a binding source bound to the list, and a combo box bound to the binding source with some fields editing whatever the bindingSource.Current is. What I would like to do is if a bool is set pop up a dialog asking if they want to save changes before they change items. If they say no I want to call CancelEdit() if yes I want to keep them on the current item so they can click the save button. How do I do this?
The second part of my question is because my underlining data source is a List<View> will CancelEdit() even do anything? (View is just a class with string Name and a List<CustomColumn>
Edit:
Let me elaborate on what I am doing to maybe help explain what I am doing.
I have a list of View, these elsewhere in the program will be enumerated to generate a DataGridView. What this menu is for is adding new "Views" and changing the order of the columns in the view (it never actually edits the the CustomColumn just adding items and changing the order of the list<CustomColumn>). What I want to happen is if someone presses cancel or changes to a new view by using the combo box without saving it will undo any changes they made to the List<CustomColumn>

If I infer your question correctly, then the answer is not one that you're going to like; the ComboBox has no mechanism for cancelling a change of selection. I wish it did, as I have come across this issue time and time again. This is how i'd work around the limitation:
bool ignoreEvent = false;
object lastSelectedItem = null;
void comboBox1_SelectedIndexChanged(object sender, EventArgs e) {
if (ignoreEvent) return;
if (CheckForChanges()) {
if (MessageBox.Show("Do you want to save changes?", "Save changes", MessageBoxButtons.YesNo) == DialogResult.Yes) {
ignoreEvent = true;
comboBox1.SelectedItem = lastSelectedItem;
ignoreEvent = false;
}
else {
// call CancelEdit() here
}
}
lastSelectedItem = comboBox1.SelectedItem;
}
Basically, the above code offers the means to revert the ComboBox to its previous selected value, without calling any event handler code in the process. Users will briefly see their item selection change, then snap back if they answer 'No' on the popup.
Also, you're correct in your assertion that CancelEdit() will essentially do nothing - the generic List collection does not support change detection. You may wish to use a DataTable or an ObservableCollection, both of which support change detection.

Related

How to automatic add the first line of text from a list box to a text box

Right I have got a list box which contains a list of tracks and when the track is pressed it moves to a second list box, what I now need to happen is have the first item that's in the second list box move automatic to a text box.
This is my current code for the first move
private void genreListBox_DoubleClick(object sender, EventArgs e)
{
playlistListBox.Items.Add(genreListBox.SelectedItem);
}
I am thinking it should be something like this
presentlyPlayingTextBox.AppendText(playlistListBox.);
But I'm not sure how to add the first line without clicking it.
I have tried this but I get an error for the value.
presentlyPlayingTextBox.Text = playlistListBox.SelectedItem.Value;
Normally you would use something like the 'SelectedIndexChanged' or 'SelectedValueChanged' action of a listbox, otherwise events like DoubleClick will fail if the keyboard is used to change the selection.
Also that event should be triggered on the second listbox when it is changed by the first.
EDIT:
On a standard Listbox, there is no .SelectedItem.Value, only .SelectedItem.
However as a listbox holds objects, not just text, you need to say you want the text value.
presentlyPlayingTextBox.Text = playlistListBox.SelectedItem.ToString();
I don't know if I fully understand your question, but if you're just attempting to move the first item from ListBox_2 to a textbox, would the following work?
presentlyPlayingTextBox.Text = playlistListBox.Items[0]?.Value; // C# >= 6
presentlyPLayingTextBox.Text = ((playlistListBox.Items == null) ? playlistListBox.Items[0].Value : "" ); // C# < 6
You could also create your own delegate/event that would fire when the user did some action.

Detect change in RadGrid item expand/collapse state

I have a RadGrid displaying a hierarchical structure. I want to save the expand/collapse state of each item in the grid so that when the user returns to the site, everything looks exactly as they left it. I have code to save and restore the state of expanded/collapsed items, however, I now need a way to detect which item is currently being expanded/collapsed when the user clicks on the expand/collapse icon. I know there's a command event, but there is no command argument nor does there seem to be any indication of which item's state is being changed. Any ideas?
I found that the GridCommandEventArgs passed into the RadGrid.ItemCommand event contains an 'Item' property that represents the item that was expanded/collapsed. If casted to a GridDataItem, one can retrieve the data key and do whatever manipulation is necessary.
protected void RadGrid_OnItemCommand(object sender, GridCommandEventArgs e)
{
try
{
if(e.CommandName.Equals("ExpandCollapse"))
{
string id = ((GridDataItem)e.Item).GetDataKeyValue("ID").ToString();
// ... do work on id (i.e. save state, etc.) ...
}
} catch(Exception ex)
{
// What could possibly go wrong? :)
}
}
Use Persistance Framework.
In my post here:
http://www.telerik.com/community/forums/wpf/persistence-framework/presistenceframework-not-save-groups.aspx#2248287
there is example how to do this.

C# need to add data to a field when a record is touched

I've built a form that has a listbox on the left side, and a bunch of text fields on the right for each field in the data source.
When the user clicks on an entry on the left it moves to that record so they can modify the fields on the right. All works fine up to this point.
The problem is that each user has a unique ID number and once they start typing in the record fields I want to populate a hidden field with their ID number so when they save, I know who touched that record.
I cannot find a suitable event to handle this method. I am not using a datagrid, I simply dragged members from the data sources window onto the form accordingly. CurrentChanged and CurrentItemChanged fire off when switching between items on the listbox so these don't reflect the behavior I need.
Any thoughts?
I feel this is a somewhat ugly answer, but it gets the job done without major any major effort. Once everything has been validated and the binding source EndEdit function has been called, you may check the DataSet for changed rows.
Before_Update handles this logic and looks at each row if changes have been made, making the necessary modifications to columns before calling UpdateAll.
Checking for Changed Rows -
http://msdn.microsoft.com/en-US/library/czb9z269%28v=VS.80%29.aspx
// Save event
private void clientBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.clientBindingSource.EndEdit();
Before_Update();
this.tableAdapterManager.UpdateAll(this.dP_TestDataSet);
}
// Place logic in here to modify records if they are changed
private void Before_Update()
{
if (dP_TestDataSet.HasChanges())
{
for (int tRow = 0; tRow < dP_TestDataSet.Tables["Client"].Rows.Count; tRow++)
{
// Modification Logic
if (dP_TestDataSet.Tables["Client"].Rows[tRow].RowState == DataRowState.Modified)
{
dP_TestDataSet.Tables["Client"].Rows[tRow]["userID"] = Program.SYSNG.UserID;
}
// Addition Logic
if (dP_TestDataSet.Tables["Client"].Rows[tRow].RowState == DataRowState.Added)
{
// Addition Logic
// ...
}
// Other RowStates such as Deleted, Detatched or Unchanged work here too
}
}
}
This successfully solves my problem though I am hoping someone comes along to trump this answer. I feel that I am doing extra work that the framework has hidden somewhere under the sheets on me and hope someone can provide me insight to this functionality.

CheckedListBox - How to programmatically ensure that one and only one item can be checked at any given time?

I want to use a CheckedListBox in an application where each item in the ListBox is the name of a folder on my hard drive and for the purpose of reading and writing text files to and from each of these folders I want to ensure that one and only one item (a folder) can be selected at any one time in the CheckedListBox
How can I achieve this via code in C#?
Thanks for reading :-)
Edit \ Update - 22/10/2010
Thanks to all who took the time to reply - especially Adrift whose updated code as requested is working perfectly.
I do appreciate what some commentators said about my usage of a checkedlistbox in this manner, however I feel it suits my purposes perfectly in that I want there to be no doubt whatsoever as to where the text files will be read from and written to.
All the best.
I agree with the comments that radio buttons would be the usual UI element when only a single item is 'checked', but if you want to stick with a CheckedListBox for your UI, you can try something like this:
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
CheckedListBox.CheckedIndexCollection checkedIndices = checkedListBox1.CheckedIndices;
if (checkedIndices.Count > 0 && checkedIndices[0] != e.Index)
{
checkedListBox1.SetItemChecked(checkedIndices[0], false);
}
}
You also might want to set CheckOnClick to true for the CheckedListBox.
Edit
Updated the code per your comment to deselect an item if it is unchecked. The problem is that unchecking the previously checked item causes the event to fire again. I don't know whether there is a standard way to handle this, but in the code below, I detach the handler before calling SetItemCheck, then reattach the handler. It seems like a clean way to handle this, and it works. If I find that there is a recommended way to handle this, I will update my answer.
HTH
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
CheckedListBox.CheckedIndexCollection checkedIndices = checkedListBox1.CheckedIndices;
if (checkedIndices.Count > 0)
{
if (checkedIndices[0] != e.Index)
{
// the checked item is not the one being clicked, so we need to uncheck it.
// this will cause the ItemCheck event to fire again, so we detach the handler,
// uncheck it, and reattach the handler
checkedListBox1.ItemCheck -= checkedListBox1_ItemCheck;
checkedListBox1.SetItemChecked(checkedIndices[0], false);
checkedListBox1.ItemCheck += checkedListBox1_ItemCheck;
}
else
{
// the user is unchecking the currently checked item, so deselect it
checkedListBox1.SetSelected(e.Index, false);
}
}
}

Selecting a TreeView Item without invoking SelectedItemChanged?

In my app, I have a group of 3d objects and they're exposed to the user through a TreeView. When a user selects an item in the TreeView, an SelectedItemChanged event is fired, the corresponding 3d object is set to be selected and is highlighted in the 3d render window. This works fine.
What I'm having trouble with is the reverse. In a section of my code, I programatically set the selected 3d object in the scene. I want to reflect the currently selected object in the TreeView, so I run through the items until I find the corresponding one. But once I get to it, I can't find a way to make the item appear selected without having SelectedItemChanged being called, which is not what I want.
Is there a way to do this?
Thanks!
I take it you want to suppress the code in your event-handler? If so, a common way of doing this is with a boolean flag (or sometimes an int counter):
bool updatingSelected;
void SomeHandler(object sender, EventArgs args) { // or whatever
if(updatingSelected) return;
//...
}
void SomeCode() {
bool oldFlag = updatingSelected;
updatingSelected = true;
try {
// update the selected item
} finally {
updatingSelected = oldFlag;
}
}
Would it be appropriate to remove the TreeView's SelectedItemChanged event handler temporarily, and re-add it once you've performed the necessary operations? I haven't tried it myself, but it's the only other thing I can think of (Marc Gravell beat me to my original answer - I've done THAT before ;) ).
Good luck!

Categories