How to access selected index change on dropdown? - c#

I am new to C# and I created a user control similar to the person from this thread:
add user control to a form
only, I used 4 dropdowns. I created a custom user control whose class is called CustomBaseUserControl.cs. It has all the selected index changed events for each dropdown. From the the form, call it TheFormControl, that the CustomBaseUserControl was dropped into, how do I access those event change values?
Thanks in advance!

If you need to retrieve selected index on TheFormControl, you could either
Use variables to store the value on CustomBaseUserControl, in this case you'll have to listen the SelectedIndexChanged events and updates your values.
Trigger a custom selected index changed from CustomBaseUserControl to TheFormControl
--
class CustomBaseUserControl: UserControl{
int idx1=-1;
public CustomBaseUserControl()
{
Initialize();
//Fill ComboBox
//Suscribe Event
combobox1.SelectedIndexChanged += combobox1_SelectedIndexChanged;
}
void combobox1_SelectedIndexChanged(object sender, EventArgs e)
{
int index = combobox1.SelectedIndex;
if (index != idx1)
{
idx1=index;
RaiseIndexChanged(e);
}
}
public virtual void RaiseIndexChanged(EventArgs ea)
{
var handler = OnIndexChanged;
if (OnIndexChanged != null)
OnIndexChanged(this, ea);
}
public event EventHandler OnIndexChanged;
}
Caller class would be
class TheFormControl: Form
{
CustomBaseUserControl cb;
public TheFormControl()
{
Initialize();
cb = new CustomBaseUserControl();
cb.OnIndexChanged +=cb_OnIndexChanged;
}
void cb_OnIndexChanged(object sender, EventArgs e)
{
// Here you know index has changed on CustomBaseUserControl
}
}

Related

Drag an item in listview to a form

I have two forms; one of them is containing listview, and another one is just a form.
I want to make a thing :
If I drag an item in listview to a Form, a messagebox would be pop up.
and the message would be text of the item.
However I don't know why 'SelectedItem' is null. When I trace the SelectedItem, it was null.
I found I have to use MouseDown and DragDrop events, but I have no idea how to use.
First one is the listview's code :
rListCtrl.MouseDown += rListCtrl_MouseDown;
rListCtrl.DragDrop += rListCtrl_DragDrop;
private void rListCtrl_MouseDown(object sender, MouseEventArgs e)
{
StringBuilder sb = new STringBuilder();
sb.Append(radListView1.SelectedItem.ToString());
testName = sb.ToString();
}
private void rListCtrl_DragDrop(object sender, DragEventArgs e){
{
MessageBox.Show(testName);
}
radListView1 is the name of listview.
The reason why SelectedItem is null, is that the Item only gets selected when you actually perform a click, not a mere MouseDown.
You can, however, use the IndexFromPoint method to get the Item the mouse had been placed on when the MouseDown Event was evoked:
private void radListView1_MouseDown(object sender, MouseEventArgs e)
{
int index = radListView1.IndexFromPoint(e.Location);
radListView1.SelectedIndex = index;
testName = radListView1.Items[index].ToString();
}
private void rListCtrl_DragDrop(object sender, DragEventArgs e){
{
MessageBox.Show(testName);
}
Form1:
public partial class Form1 : Form
{
Form2 f = new Form2();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
f.Show();
}
private void Form1_MouseEnter(object sender, EventArgs e)
{
if(f.data!= string.Empty)
{
MessageBox.Show(f.data);
f.data = string.Empty;
}
}
}
Form2:
public partial class Form2 : Form
{
public string data = string.Empty;
public Form2()
{
InitializeComponent();
listView1.ItemDrag += doDaragItem;
}
private void doDaragItem(Object sender, ItemDragEventArgs e)
{
data = e.Item.ToString();
}
}
Ron,
RadListView from the Telerik UI from WinForms suite handles the whole drag and drop operation by its ListViewDragDropService. Its PreviewDragOver event allows you to control on what targets the item(s) being dragged can be dropped on. The PreviewDragDrop event allows you to get a handle on all the aspects of the drag and drop operation, the source (drag) list view, the destination (target) control, as well as the item being dragged. Additional information is available in the following help article: https://docs.telerik.com/devtools/winforms/controls/listview/drag-and-drop/listviewdragdropservice
https://docs.telerik.com/devtools/winforms/controls/listview/drag-and-drop/drag-and-drop-using-raddragdropservice
You can also combine the RadDragDropService and OLE drag-and-drop functionality: https://docs.telerik.com/devtools/winforms/controls/listview/drag-and-drop/combining-raddragdropservice-and-ole-drag-and-drop
As to the specific code snippet, indeed, if you don't have a selected item in RadListView, the code in the MouseDown event won't extract the item's text. You need to get the element under the mouse and set the item as selected:
private void radListView1_MouseDown(object sender, MouseEventArgs e)
{
SimpleListViewVisualItem elementUnderMouse = this.radListView1.ElementTree.GetElementAtPoint(e.Location) as SimpleListViewVisualItem;
if (elementUnderMouse != null)
{
this.radListView1.SelectedItem = elementUnderMouse.Data ;
}
StringBuilder sb = new StringBuilder();
sb.Append(radListView1.SelectedItem.Text.ToString());
{
testName = sb.ToString();
}
MessageBox.Show(testName);
}
I hope this information helps.

Any easy way to alert to changes in multiple text boxes?

I'm fairly new to programming so sorry if this is simple, but I might just be missing the obvious! I have the following form which is automatically populated on load from settings stored in an INI file:
The whole form is working just as I want it to apart form one small part. The 'Close' button currently just closes the form so that if any values have changed in the text boxes since the form was loaded, the changes are lost. I want to instead prompt the user to use the Save button instead otherwise the changes will be lost.
I've been trying to do something along these lines on my close button where the value of the text boxes are checked against the variable values that they were originally populated with:
private void btnClose_Click(object sender, EventArgs e)
{
if (txtName.Text != name || txtSchName.Text != schname || txtServer1.Text != svr1 etc etc etc)
{
Warn User changes will be lost, ask user if really OK to close?
if (User chooses to to close)
{
this.Close();
}
else
{
Go back to the config form;
}
}
else
{
this.Close();
}
With over 21 text fields, I was not sure if this was the most "tidy way" of checking for changes? Any pointers would be appreciated.
You just add a global boolean variable and write an handler for the TextChanged event
// Declared at the form level
private bool _modified = false;
public Form1()
{
InitializeComponent();
// This could be done in the form designer of course
// o repeated here for every textbox involved....
txtName.TextChanged += OnBoxesChanged;
......
}
private void Form1_Load(object sender, EventArgs e)
{
.....
// Code that initializes the textboxes could raise the TextChanged event
// So it is better to reset the global variable to an untouched state
_modified = false;
}
private void OnBoxesChanged(object sender, EventArgs e)
{
// Every textbox will call this event handler
_modified = true;
}
private void btnClose_Click(object sender, EventArgs e)
{
if(_modified)
{
// Save, warning, whatever in case of changes ....
}
}
Just set the event handler OnBoxesChanged for every textbox you want to trigger the condition. You could do it through the Designer or manually after the InitializeComponent call
What you are looking for is Dirty Tracking. Dirty tracking is used to track states of your control. Here is a simple reusable approach to track your controls
public class SimpleDirtyTracker
{
private Form _frmTracked;
private bool _isDirty;
public SimpleDirtyTracker(Form frm)
{
_frmTracked = frm;
AssignHandlersForControlCollection(frm.Controls);
}
// property denoting whether the tracked form is clean or dirty
public bool IsDirty
{
get { return _isDirty; }
set { _isDirty = value; }
}
// methods to make dirty or clean
public void SetAsDirty()
{
_isDirty = true;
}
public void SetAsClean()
{
_isDirty = false;
}
private void SimpleDirtyTracker_TextChanged(object sender, EventArgs e)
{
_isDirty = true;
}
private void SimpleDirtyTracker_CheckedChanged(object sender, EventArgs e)
{
_isDirty = true;
}
// recursive routine to inspect each control and assign handlers accordingly
private void AssignHandlersForControlCollection(
Control.ControlCollection coll)
{
foreach (Control c in coll)
{
if (c is TextBox)
(c as TextBox).TextChanged
+= new EventHandler(SimpleDirtyTracker_TextChanged);
if (c is CheckBox)
(c as CheckBox).CheckedChanged
+= new EventHandler(SimpleDirtyTracker_CheckedChanged);
// ... apply for other desired input types similarly ...
// recurively apply to inner collections
if (c.HasChildren)
AssignHandlersForControlCollection(c.Controls);
}
}
and in your mainform
public partial class Form1 : Form
{
private SimpleDirtyTracker _dirtyTracker;
private void Form1_Load(object sender, EventArgs e)
{
_dirtyTracker = new SimpleDirtyTracker(this);
_dirtyTracker.SetAsClean();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// upon closing, check if the form is dirty; if so, prompt
// to save changes
if (_dirtyTracker.IsDirty)
{
DialogResult result
= (MessageBox.Show(
"Would you like to save changes before closing?"
, "Save Changes"
, MessageBoxButtons.YesNoCancel
, MessageBoxIcon.Question));
}
}
If you want to save for example usersettings you could create Settings in your Properties.
You can get them like this:
string anyProperty = WindowsFormsApplication1.Properties.Settings.Default.TestSetting;
You save them using the Save-method:
WindowsFormsApplication1.Properties.Settings.Default.TestSetting = "Hello World";
WindowsFormsApplication1.Properties.Settings.Default.Save();
You can call the Save-method after you have clicked the close-button.
For saving several string properties you could create a property of the type System.Collections.Specialized.StringCollection, so that you just create one property and not 21.
One disadvantage of dirtytracer is, that it returns "dirty" even when changes revert to original state. If You use object in DataContext as Your data model, all this task simplifies to:
bool changed = dataContext.SomeTables.GetModifiedMembers(someRow).Any();

How to prevent TextChanged event when I select an item in combobox?

I have a TextChanged event on my ComboBox like;
private void comboBox1_TextChanged(object sender, EventArgs e)
{
foreach (var item in comboBox1.Items.Cast<string>().ToList())
{
comboBox1.Items.Remove(item);
}
foreach (string item in InputBox.AutoCompleteCustomSource.Cast<string>().Where(s => s.Contains(comboBox1.Text)).ToList())
{
comboBox1.Items.Add(item);
}
}
As an explanation, when I change the text of combobox, I want to get string values contains in AutoCompleteCustomSource on InputBox (which is TextBox).
It works fine when I search them but when I select the item, obviously TextChanged event triggered again and Text property of Combobox will reset.
How to solve this?
If I understood correctly then i think you want to hide the TextChange event of the combobox. If it is then you can create a custom control inherited by ComboBox and override the TextChange event.
public partial class MyCombo : ComboBox
{
public MyCombo()
{
InitializeComponent();
}
bool bFalse = false;
protected override void OnTextChanged(EventArgs e)
{
//Here you can handle the TextChange event if want to suppress it
//just place the base.OnTextChanged(e); line inside the condition
if (!bFalse)
base.OnTextChanged(e);
}
protected override void OnSelectionChangeCommitted(EventArgs e)
{
bFalse = true;
base.OnSelectionChangeCommitted(e);
}
protected override void OnTextUpdate(EventArgs e)
{
base.OnTextUpdate(e);
bFalse = false; //this event will be fire when user types anything. but, not when user selects item from the list.
}
}
EDITED:
Another simple soution is use TextUpdate event instead of TextChange and keep your combobox as it is without creating another custom control.
private void myCombo1_TextUpdate(object sender, EventArgs e)
{
foreach (var item in myCombo1.Items.Cast<string>().ToList())
{
myCombo1.Items.Remove(item);
}
foreach (string item in myCombo1.AutoCompleteCustomSource.Cast<string>().Where(s => s.Contains(myCombo1.Text)).ToList())
{
myCombo1.Items.Add(item);
}
}
TextUpdate event will call only when user types anything in combobox. But, not when user selects item from the drop down list. So, this will not resent the added items.
You can also change the where condition if you wish to return all matched items in both cases(Upper and Lower). Suppose you have a two items in the list 1. Microsoft Sql Server, 2. microsoft office then what would be the result if i type microsoft only.
Where(s => s.ToLower().Contains(comboBox1.Text.ToLower()))
Sample Code
As #Sayse already said:
Add a boolean:
private bool codeCalled = new bool();
In your textChanged:
if(codeCalled == true)
{
codeCalled = false;
return;
}
else
{
codeCalled = true;
//your foreachcode here
}
That should do the trick.
Tested and is working.
Also tested and working, also not elegant:
private void textBox_TextChanged(object sender, EventArgs e)
{
textBox.TextChanged -= textBox_TextChanged;
//yourcode
textBox.TextChanged += textBox_TextChanged;
}

C# WinForms ListView Item Count Change Event

Is there an event in Win Forms that can fire when the count of items in ListView change? I tried Size and Text - oddly enough they "sorta" worked but not always...
Im trying to trigger a label to update with the count of the listview items as it changes without manually doing that in a hundred methods.
If you are not using a bound datasource you can create a wrapper around the ListView Control and add a Method and an Event to fire off an event on adding an item to your ListView Collection.
Custom ListView
public class customListView : ListView
{
public event EventHandler<CustomEventArgs> UpdateListViewCounts;
public void UpdateList(string data)
{
// You may have to modify this depending on the
// Complexity of your Items
this.Items.Add(new ListViewItem(data));
CustomEventArgs e = new CustomEventArgs(Items.Count);
UpdateListViewCounts(this, e);
}
}
public class CustomEventArgs : EventArgs
{
private int _count;
public CustomEventArgs(int count)
{
_count = count;
}
public int Count
{
get { return _count; }
}
}
Example Usuage
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
customListView1.UpdateListViewCounts+=customListView1_UpdateListViewCounts;
}
private void customListView1_UpdateListViewCounts(object sender, CustomEventArgs e)
{
//You can check for the originating Listview if
//you have multiple ones and want to implement
//Multiple Labels
label1.Text = e.Count.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
customListView1.UpdateList("Hello");
}
}

Text box value are not accessing in asp.net c#

i have a textbox on .aspx page..On this page there is a user control .Inside this user contrl there is a button .I want o get the value of text box on button click which is not inside the user control .How can i do this
Please Help me .
write this line in you button click event of user control
protected void Button_Click(sender obj,EventArgs arg)
{
TextBox txtbox= (((MyPage)parent).FindControl("TextBoxid") as TextBox);
if(txtbox!=null)
(((MyPage)this.Page).FindControl("TextBoxid") as TextBox).Text;
//or
//(((MyPage)this.Parent).FindControl("TextBoxid") as TextBox).Text;
}
or
alternative is create the property in your page and access it in your user control
public string txtValue
{
get
{
return TextboxID.Text;
}
}
in button click event of user control
protected void Button_Click(sender obj,EventArgs arg)
{
string txtvalue = ((Mypage)this.Page).txtValue;
//or
//((MyPage)this.Parent).txtValue;
}
protected void MyButton_Click(object sender, EventArgs e)
{
string TextBoxValue;
TextBoxValue = MyTextBox.Text;
}
Is it what you want ?
Try use the following method,
((TextBox)USerControl.Parent.FindControl("txtbox")).Text
((TextBox)USerControl.Page.FindControl("txtbox")).Text
or
((YourPageType)USerControl.Page).TextBox.Text
With de-coupling in mind, I would recommend that if your user control needs to access information outside of it, then that information should passed in, not vice versa. The control shouldn't be responsible for where the information comes from, it just knows there is information. With this in mind, I would recommend bubbling the event to get the required information.
Event Bubbling
This will involve creating a new delegate, and then triggering it once the Button has been clicked, thus bubbling the event and allowing us to return the desired value, which in this case is the textbox value.
Step 1: Declare the delegate
// declare a delegate
public delegate string MyEventHandler(object sender, EventArgs e);
Step 2: Update the user control
// update the user control
public class MyUserControl : UserControl
{
// add the delegate property to your user control
public event MyEventHandler OnSomeButtonPressed;
// trigger the event when the button is pressed
protected void MyButton_Click(object sender, EventArgs e)
{
string someString = string.Empty;
if (this.OnSomeButtonPressed != null)
{
someString = this.OnSomeButtonPressed(this, e);
}
// do something with the string
}
}
Step 3: Update the page
// be sure to register the event in the page!
public class MyPage : Page
{
protected override void OnLoad(object sender, EventArgs e)
{
base.OnLoad(sender, e);
myUserControl.OnSomeButtonPressed += this.HandleUserControl_ButtonClick;
}
public string HandleUserControl_ButtonClick(object sender, EventArgs e)
{
return this.SomeTextBox.Text;
}
}

Categories

Resources