Is there an event or command I could use so I can invoke the object that is getting added to the ObservableCollection before it gets added?
At the moment, once the user clicks the row in the grid, it adds it to the collection, however I need to specifically assign properties in C# that I don't want to assign in the grid.
public void event
{
// I want to do something before the CanUserAddRow event does this
collection.Add(<T>;
}
You can use DataGrid.InitializingNewItem event:
private void InitializingNewItem(object sender, InitializingNewItemEventArgs e)
{
//use e.NewItem here
}
From MSDN
You can set default values for the new item by handling the InitializingNewItem event and setting the values programmatically
I'm not exactly sure is that work for you...
private void DataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
YourObject obj = e.Row.Item as YourObject;
if (obj != null)
{
//see obj properties
}
}
Explanation :
In here after user enter the data to the grid, and It takes as e.Row.Item Then you can change any of modification to your object.
Related
I have 20 items in a List<myObject>. Each has an instance of a UserControl associated with it. Each object is accessible via a MenuStrip that needs to display the UserControl when the appropriate item is clicked. Currently I have an event handler for each of them, which works, but I was wondering if a way exists to simplify this and use a single event handler for all of the items.
Is this possible? If so what is the best way to go about doing so.
EDIT:Can anybody else provide any input on this issue? I'm having trouble with Mailo's answer. Essentially all I need to do is make an event handler that can display the appropriate UserControl stored in a List<myObject> as a property when the correct MenuStrip item is clicked. Is there a more straightforward way to do this? Ideally I'd like to make it so that a foreach loop can go through the list and set up the handlers.
Is there nobody who can help me with this?
It's not very difficult. First is you need some way to associate a menu item with a control in the list.
1) Since you have a list, index is simplest way ( you could use Dictionary<> to simplify this association). So, lets say when you click the first menu item, you want myObjecList[0] to appear. When you click second MenuItem, myObjectList[1] would appear and so on. For this go to each menu item, and in the Properties, assign a value to Tag property. For first menu item, assign Tag to 0, for second item, assign Tag to 1 - and so on.
2) Create one event handler and assign the same handler to all menu items. The event handler could look something like this:
private void myToolStripMenuItem_Click(object sender, EventArgs e)
{
// source menu item which was clicked
ToolStripMenuItem item = sender as ToolStripMenuItem;
if(item != null)
{
int index = int.Parse(item.Tag.ToString()); // get the index from Tag
myObject control = myObjectList[index];
// do your stuff with your control
}
}
you can pass the sender object to your event handler and check for the type inside the handler
it will be something like this
//this will contain any properties you wanna send to the handler
public class MyHandlerEventArgs : EventArgs
{
}
//this delegate gets the sender, you can change the sender type to be the encapsulated type of your controls
public delegate void MyHandler(object sender, MyHandlerEventArgs args);
//this is the class that fires the event in your case it will UI class I think
public class MyController
{
public event MyHandler myEvent;
public void MyEvent_Fire()
{
if(myEvent != null)
myEvent(this, new MyHandlerEventArgs());
}
}
//here you can do your business logic for each control
public class MyAction
{
MyController mc = new MyController();
public MyAction()
{
mc.myEvent += new MyHandler(mc_myEvent);
}
void mc_myEvent(object sender, MyHandlerEventArgs args)
{
//check the sender type
//do your action
}
}
this link might be useful to
check
You might want the ItemClicked event from the MenuStrip. You can use the ClickedItem from the ToolStripItemClickedEventArgsto find your UserControl
Some pseudocode:
// Initialize
myMenuStrip.ItemClicked += itemClickedEvent;
// ...
void itemClickedEvent(Object sender, ToolStripItemClickedEventArgs e)
{
int index = myObjectList.FindIndex(e => e.instanceOfUserControl == e.ClickedItem);
// Now that we have the clicked item, display it how we would in an individual event handler.
myObjectList[index].instanceOfUserControl.DoDisplay();
}
Ideally I'd like to make it so that a foreach loop can go through the list and set up the handlers.
For this approach you'd use a foreach on the List
foreach (var listItem in myObjectList)
{
listItem.TheEvent += myEventHandler;
}
I have a listbox in which a have a series of cases retrieved from a database. When i create a new case i wan't to update the listBox to reflect the actual state of the cases-table in the database. But I get a NullReferenceException from the event handler for this line: populateBoxes((int)lb.SelectedValue) when i try to update it.
This is my event-handler on the listbox:
private void lbCases_SelectedIndexChanged(object sender, EventArgs e)
{
ListBox lb = (ListBox)sender;
populateBoxes((int)lb.SelectedValue);
}
The update event:
private void button1_Click(object sender, EventArgs e)
{
this.casesTableAdapter.Fill(this.caseDB.cases);
}
I've used the built-in feature of VSE2008 to set the datasource, displaymember and valuemember of the listbox.
You have to make sure that when the datasource is set the lbCases_SelectedIndexChanged either does not fire or ignores the event.
Either create a 'Loading' boolean to ignore the event or set the index to -1 and add a check in lbCases_SelectedIndexChanged for the -1 index value to prevent the exception.
Set the selectedindex to -1 and then populate the list box over.
I suggest, you do a check in that event handler:
private void lbCases_SelectedIndexChanged(object sender, EventArgs e)
{
ListBox lb = sender as ListBox;
if(lb == null)
return;
populateBoxes((int)lb.SelectedValue);
}
Check the SelectedValue for null before you run the
if (lb.SelectedValue != null)
{
populateBoxes((int)lb.SelectedValue);
}
Also, if you want to end up with a selected value, you will have to select it after you call:
this.casesTableAdapter.Fill(this.caseDB.cases);
I have a C# ComboBox using WPF. I have code that executes when the ComboBox's GotFocus is activated. The issue is that the GotFocus event is executed every time a selection is made from the ComboBox. For example, the GotFocus is executed when you first click on the ComboBox and then when you make a selection even though you have not click on any other control.
Is it possible to prevent this event from firing if a selection is being made in the list or is there a flag or something else in the event handler that can be used to determine if the GotFocus event handler was fired as a result of the user selecting an item in the list?
You can solve this problem with next verification:
private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() == typeof(ComboBoxItem))
return;
//Your code here
}
This code will filter all focus events from items (because they use bubble routing event). But there is another problem - specific behaviour of WPF ComboBox focus: when you open drop-down list with items your ComboBox losing focus and items get. When you select some item - item losing focus and ComboBox get back. Drop-down list is like another control. You can see this by simple code:
private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
{
Trace.WriteLine("Got " + DateTime.Now);
}
}
private void myComboBox_LostFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
{
Trace.WriteLine("Lost " + DateTime.Now);
}
}
So you will get anyway atleast two focus events: when you select ComboBox and when you selecting something in it (focus will return to ComboBox).
To filter returned focus after selecting item, you can try to use DropDownOpened/DropDownClosed events with some field-flag.
So the final code with only 1 event of getting focus:
private bool returnedFocus = false;
private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem) && !returnedFocus)
{
//Your code.
}
}
private void myComboBox_LostFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
{
ComboBox cb = (ComboBox)sender;
returnedFocus = cb.IsDropDownOpen;
}
}
Choose from this examples what you actually need more for your application.
I'm not too hot on WPF; but if you're trying to detect changes to the list (click on new value etc) you can use SelectedIndexChanged events..
On the other hand, if you really do want to know simply when the control is focussed, can you filter it by saying something like;
if (combo1.Focused && combo1.SelectedIndex == -1)
{
...
}
.. ? It really depends on what youre trying to detect, exactly.
Another solution is used is to determine whether the new focused element is an existing item in the combobox. If true then the LostFocus event should not be performed, because the combobox still has focus. Otherwise an element outside the combobox received focus.
In the code snipplet below I added the functionality in a custom combobox class
public class MyComboBox : System.Windows.Controls.Combobox
{
protected override void OnLostFocus(RoutedEventArgs e)
{
//Get the new focused element and in case this is not an existing item of the current combobox then perform a lost focus command.
//Otherwise the drop down items have been opened and is still focused on the current combobox
var focusedElement = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this));
if (!(focusedElement is ComboBoxItem && ItemsControl.ItemsControlFromItemContainer(focusedElement as ComboBoxItem) == this))
{
base.OnLostFocus(e);
/* Your code here... */
}
}
}
I come from the VBA world, and remember there was a BeforeUpdate call I could make on a combobox. Now I am in C# (and loving it) and I was wondering is there a BeforeUpdate call for a ComboBox on a Winform?
I can make an invisible textbox and store the info I need there and after the update, look at that box for what I need, but I was hoping there was a simplier solution.
One of the goodies of WF is that you can easily make your own. Add a new class to your project and paste the code below. Compile. Drop the new control from the top of the toolbox onto your form. Implement the BeforeUpdate event.
using System;
using System.ComponentModel;
using System.Windows.Forms;
public class MyComboBox : ComboBox {
public event CancelEventHandler BeforeUpdate;
public MyComboBox() {
this.DropDownStyle = ComboBoxStyle.DropDownList;
}
private bool mBusy;
private int mPrevIndex = -1;
protected virtual void OnBeforeUpdate(CancelEventArgs cea) {
if (BeforeUpdate != null) BeforeUpdate(this, cea);
}
protected override void OnSelectedIndexChanged(EventArgs e) {
if (mBusy) return;
mBusy = true;
try {
CancelEventArgs cea = new CancelEventArgs();
OnBeforeUpdate(cea);
if (cea.Cancel) {
// Restore previous index
this.SelectedIndex = mPrevIndex;
return;
}
mPrevIndex = this.SelectedIndex;
base.OnSelectedIndexChanged(e);
}
finally {
mBusy = false;
}
}
}
You may consider SelectionChangeCommited.
From MSDN:
SelectionChangeCommitted is raised
only when the user changes the combo
box selection. Do not use
SelectedIndexChanged or
SelectedValueChanged to capture user
changes, because those events are also
raised when the selection changes
programmatically.
This won't work when you have set your combobox to allow the user to type in the textbox though. Also, it won't tell you what the 'last' selected item was. You will have to cache this information. However, you don't need to store your information in a textbox. You can use a string.
You could try ValueMemberChanged, Validating, SelectedIndexChanged, or TextChanged. They don't fire like the BeforeUpdate, but you can look at what will be updated and handle the updated, or refuse it.
Out of the box, there's nothing like that. All of the events that deal with change in the combo box happen after the new value is already selected. At that point there's no way to tell what the value USED to be. You're best bet is what you eluded to. As soon as your ComboBox is populated save the SelectedItem to a temporary variable. Then, hook into the SelectedValueChanged event. At that point, your temporary variable will be your old value, and the SelectedItem will be your current value.
private object oldItem = new object();
private void button3_Click(object sender, EventArgs e)
{
DateTime date = DateTime.Now;
for (int i = 1; i <= 10; i++)
{
this.comboBox1.Items.Add(date.AddDays(i));
}
oldItem = this.comboBox1.SelectedItem;
}
private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
//do what you need with the oldItem variable
if (oldItem != null)
{
MessageBox.Show(oldItem.ToString());
}
this.oldItem = this.comboBox1.SelectedItem;
}
I think what you wanted was the DropDown event. It will tell you what the value is before the user changes it. However, the user may end up not changing anything, so it's not exactly the same as BeforeUpdate.
I've got two ListBox'es that are databound to the same BindingList.
The issue is that when changing the selected item from the GUI it's changing the position in the BindingList and then the BindingList signals the other ListBox to change its selected item.
So I've got the two ListBoxes Selected Item also synchronized which is not good for me.
I'd like to maintain the list of items in sync. without the cursor position.
How do I disable that cursor so it's not maintained?
sample code (just add two ListBoxes to the Form at design time and register the SelectedIndexChanged events and register the button click event with a button):
public partial class Form1 : Form
{
BindingList<string> list = new BindingList<string>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
list.Add("bla1");
list.Add("bla2");
list.Add("bla3");
this.listBox1.DataSource = list;
this.listBox2.DataSource = list;
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedIndex != -1)
System.Diagnostics.Trace.WriteLine("ListBox1: " + listBox1.SelectedItem.ToString());
}
private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox2.SelectedIndex != -1)
System.Diagnostics.Trace.WriteLine("ListBox2: " + listBox2.SelectedItem.ToString());
}
// Register this event to a button
private void button1_Click(object sender, EventArgs e)
{
list.Add("Test");
}
}
Thanks,
--Ran.
Add this line to Form_Load:
this.listBox1.BindingContext = new BindingContext();
Declaring listBox1 and listBox2 to be of the following type seems to result in the desired behaviour.
class MyListBox: ListBox {
protected override void OnSelectedIndexChanged (EventArgs a) {
if (DataManager != null) {
DataManager.SuspendBinding();
}
}
}
Regards,
tamberg
My solution for this issue is to use a normal List instead of the BindingList and just call (before the change) on the Form object:
this.BindingContext[Your List].SuspendBinding();
and after the change to the List
this.BindingContext[Your List].ResumeBinding();
This updates all the bounded controls.
Notice it's also noted in the MSDN link here:
"If you are bound to a data source that does not implement the IBindingList interface, such as an ArrayList, the bound control's data will not be updated when the data source is updated. For example, if you have a combo box bound to an ArrayList and data is added to the ArrayList, these new items will not appear in the combo box. However, you can force the combo box to be updated by calling the SuspendBinding and ResumeBinding methods on the instance of the BindingContext class to which the control is bound."