My application in C# has a Textbox with a txt_TextChanged event.
private void txt_TextChanged(object sender, EventArgs e)
{
//Do somthin
}
But there's one specific part that I want to change txt.Text without firing the txt_TextChanged event.
txt.Text ="somthing" //Don't fire txt_TextChanged
How can I do that?
There is no direct way to prevent the raising of events for the text property, however your event handler can use a flag to determine weather or not to perform a task. This i likely to be more efficient than attaching and detaching the event handler. This can be done by a variable within the page or even a specialized class wrapper
With a variable:
skipTextChange = true;
txt.Text = "Something";
protected void TextChangedHandler(object sender, EventArgs e) {
if(skipTextChange){ return; }
/// do some stuffl
}
With specialized event handler wrapper
var eventProxy = new ConditionalEventHandler<EventArgs>(TextBox1_TextChanged);
TextBox1.TextChanged = eventProxy.EventAction;
eventProxy.RaiseEvents = false;
TextBox1.Text = "test";
public void TextBox1_TextChanged(object sender, EventArgs e) {
// some cool stuff;
}
internal class ConditionalEventHadler<TEventArgs> where TEventArgs : EventArgs
{
private Action<object,TEventArgs> handler;
public bool RaiseEvents {get; set;}
public ConditionalEventHadler(Action<object, TEventArgs> handler)
{
this.handler = handler;
}
public void EventHanlder(object sender, TEventArgs e) {
if(!RaiseEvents) { return;}
this.handler(sender, e);
}
}
txt.TextChanged -= textBox1_TextChanged; // dettach the event handler
txt.Text = "something"; // update value
txt.TextChanged += textBox1_TextChanged; // reattach the event handler
You can extend text box and introduce there a new property that will not trigger the TextChanged event.
class SilentTextBox : TextBox
{
// if true, than the TextChanged event should not be thrown
private bool Silent { get; set; }
public string SilentText
{
set
{
try
{
Silent = true;
Text = value;
}
finally
{
Silent = false;
}
}
}
protected override void OnTextChanged(EventArgs e)
{
// raise event only if the control is in non-silent state
if (!Silent)
{
base.OnTextChanged(e);
}
}
}
try this extension method
public static class TextBoxExt
{
private static readonly FieldInfo _field;
private static readonly PropertyInfo _prop;
static TextBoxExt()
{
Type type = typeof(Control);
_field = type.GetField("text", BindingFlags.Instance | BindingFlags.NonPublic);
_prop = type.GetProperty("WindowText", BindingFlags.Instance | BindingFlags.NonPublic);
}
public static void SetText(this TextBox box, string text)
{
_field.SetValue(box, text);
_prop.SetValue(box, text, null);
}
}
you can use textbox.SetText("...") to change text and the TextChanged event will not be fired.
A quick and dirty way is to do an
ctrl.Enable = false;
ctrl.Text = "Something";
ctrl.Enable = true;
and then in the OnChange event, encapsulate the offending code with a
if (ctrl.Enabled) {
// offending code here.
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
EventHandler TextChanged_EventHandler = new EventHandler(textBox1_TextChanged);
textBox1.TextChanged -= TextChanged_EventHandler;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
MessageBox.Show("BUG");
}
}
I found a simple method, suitable for event handlers and controls that are not in the same .cs file
public static void SetTextWithoutRaiseEvent(this TextBox textBox, string content)
{
var scroll = textBox.Template.FindName("PART_ContentHost", textBox);
(scroll as ScrollViewer).Content = content;
}
Related
Here is my problem : I have one delegate which I subscribe to from another class, that's alright. What I'd like is each time something subscribe to this delegate it raise an event that tells me the invocation list has changed and how +1 or -1...
I searched for an Onchange event in invocationlist but didn't find anything..
Form1:
namespace EventsOnDelegates
{
public delegate void DEL_delegate1(Double AValue);
public delegate void DEL_delegate2(Boolean AsecondValue);
public partial class Form1 : Form
{
public DEL_delegate1 SetValueCbk;
public EventHandler InvocationListChange;
private Form2 FormwithLabel;
int invoclength;
public Form1()
{
InitializeComponent();
FormwithLabel = new Form2(this);
FormwithLabel.Show();
/*the question part*/
/*I'd like to add an onchange event that tells me if the invocation list has changed and how + or -*/
InvocationListChange += new EventHandler(SetValueCbk.GetInvocationList(),InvocationListHaschanged);
}
protected virtual void InvocationListHaschanged(object sender, EventArgs e)
{
invoclength = SetValueCbk.GetInvocationList().Length;
label1.Text = Convert.ToString(invoclength);
}
private void button1_Click(object sender, EventArgs e)
{
Random newRandNum = new Random();
Double newNumber = newRandNum.NextDouble();
SetValueCbk(newNumber);
}
}
}
Form2:
public partial class Form2 : Form
{
public Form2(){}
public Form2(Form1 Form1link)
:this()
{
InitializeComponent();
Form1link.SetValueCbk += new DEL_delegate1(this.SetValueCbkFN);
}
protected void SetValueCbkFN(Double value)
{
label1.Text = Convert.ToString(value);
}
}
Thanks for help!!
You can use explicit event declaration for that event field :
private EventHandler meEvent;
public event EventHandler MeEvent
{
add { meEvent += value; MeEventInvocationListChanged(); }
remove { meEvent -= value; MeEventInvocationListChanged(); }
}
EDIT : ( Fitting this into your question )
instead of your InvocationListHasChanged method you can create :
void InvokationListChanged(int dir)
{
string msg = dir < 0 ? "Someone unsubscribed from the event" : "Someone subscribed to the event";
if(InvokeRequired)
{
Invoke( new MethodInvoker( () => { label1.Text = msg; });
}
else
{
label1.Text = msg;
}
}
And then change public DEL_delegate1 SetValueCbk; to :
private DEL_delegate1 m_SetValueCbk;
public event Del_delegate1 SetValueCbk
{
add { m_SetValueCbk+= value; InvokationListChanged(1); }
remove { m_SetValueCbk-= value; InvokationListChanged(-1); }
}
Now whenever some other object subscribe to SetValueCbk your label1.Text will change to "Someone subscribed to the event" and whenever some object unsubscribe from SetValueCbk your label1.Text will change to "Someone unsubscribed from the event"
Here is my code in my userControl
public partial class UserControlHomeScreen : UserControl
{
public event EventHandler SomethingHappened;
public void DoSomething()
{
EventHandler handler = SomethingHappened;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
public void HandleEvent(object sender, EventArgs args)
{
MessageBox.Show("Wafak.");
}
public UserControlHomeScreen()
{
InitializeComponent();
}
private void btnAverageDailyBal_Click(object sender, EventArgs e)
{
this.Tag = 0;
this.Hide();
}
private void btnComputeTransferPricing_Click(object sender, EventArgs e)
{
this.Tag = 1;
this.Hide();
}
}
And here is my code in my main form
private void HomeScreen()
{
uHomeScreen = new UserControlHomeScreen();
uHomeScreen.Dock = DockStyle.Fill;
//uHomeScreen.Disposed += new EventHandler(uHomeScreen_Disposed);
uHomeScreen.SomethingHappened += new EventHandler(uHomeScreen_SomethingHappened);
panelMain.Controls.Add(uHomeScreen);
}
void uHomeScreen_SomethingHappened(object sender, EventArgs e)
{
MessageBox.Show("throw new NotImplementedException();");
}
What i want to happen is that when the usercontrol is hidden i want to fire an event in my main form but does not work, what am i missing? please help. thanks!
Your naming convention for event raiser (DoSomething) is confusing, your code doesn't call DoSomething (or raise the event SomethingHappened), so how could it fire for you? Add the following code in your user control class:
//override the OnVisibleChanged
protected override void OnVisibleChanged(EventArgs e){
if(!Visible) DoSomething();
}
I'm in a position where I have two classes, one has an event handler for a button and I need to be able to listen to that event handler in the other class in order to make changes in the non-button class. I don't have much experience with this type of scenario so am not quite sure where to start.
Here is an exampple of this two classes (if I understood the question right).
class Form
{
Button _button1, _button2;
public Form()
{
_button1 = new Button("button1");
_button2 = new Button("button2");
_button1.Click += _button_Click;
_button2.Click += _button_Click;
}
void _button_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
Console.WriteLine(button.Name);
}
public void Click1()
{
_button1.FireEvent();
}
public void Click2()
{
_button2.FireEvent();
}
}
class Button
{
public event EventHandler Click;
public string Name;
public Button(string name)
{
Name = name;
}
public void FireEvent()
{
Click(this, new EventArgs());
}
}
Usage:
Form f = new Form();
f.Click1();
f.Click2();
The issue I am having is that when I update my object, the ListBox automatically removes and then re-adds the object to the list, thus calling the index and value changed events. I was able to prevent this by creating a custom ListBox control and when the PropertyChangedEvent was called, I would raise a flag that would prevent those events in the base class from being called. What is happening now is that my entire reference is being replace by a new reference and unless I re-select the item in the ListBox, I have the wrong reference.
What I basically want to do, is to change the Display Value in my object and then have it update only the text in the list box. I do not want it to remove and to re-add the object/reference/whatever it does. It's quite annoying.
Here is the example code I am working with...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.myListBox1.SelectedValueChanged += this.onchange;
}
private void Form1_Load(object sender, EventArgs e)
{
this.myListBox1.Add(new strobj("z"));
this.myListBox1.Add(new strobj("a"));
this.myListBox1.Add(new strobj("b"));
this.myListBox1.Add(new strobj("f"));
this.myListBox1.Add(new strobj("n"));
this.myListBox1.Add(new strobj("h"));
this.myListBox1.Add(new strobj("p"));
this.myListBox1.Add(new strobj("t"));
this.myListBox1.Add(new strobj("c"));
this.myListBox1.Add(new strobj("q"));
}
private void onchange(object sender, EventArgs e)
{
MessageBox.Show("Hello World");
}
int i = 0;
private void button1_Click(object sender, EventArgs e)
{
if (this.myListBox1.SelectedItem != null)
{
strobj item = (strobj)this.myListBox1.SelectedItem;
item.Name1 = i++.ToString();
}
}
}
public partial class MyListBox
{
public MyListBox()
{
InitializeComponent();
}
public void Add(strobj item)
{
item.OnNameChanged += this.MyDispalyMemberChanged;
this.Items.Add(item);
}
bool refreshing = false;
public void MyDispalyMemberChanged(strobj itemChanged)
{
this.refreshing = true;
this.RefreshItem(this.Items.IndexOf(itemChanged));
this.refreshing = false;
}
protected override void OnSelectedValueChanged(EventArgs e)
{
if (!this.refreshing)
{
base.OnSelectedValueChanged(e);
}
}
}
class strobjCollection : List<strobj>
{
NameChangeEventHandler NameChangedEvent;
}
delegate void NameChangeEventHandler(strobj sender);
public class strobj
{
internal NameChangeEventHandler OnNameChanged;
private string _Name1;
public string Name1
{
get { return this._Name1; }
set
{
this._Name1 = value;
if (this.OnNameChanged != null)
{
this.OnNameChanged(this);
}
}
}
public int i = 0;
public string str = "p";
public strobj(string name)
{
this._Name1 = name;
}
public strobj()
{
this._Name1 = "You did not create this object";
}
public override string ToString()
{
return this._Name1;
}
}
This is what the INotifyPropertyChanged interface was made for.
Instead of raising your custom event, you'd raise the PropertyChanged event with the name of the property you changed set in the event args and the listbox would update.
See MSDN.
I have a GUI-thread for my form and another thread that computes things.
The form has a richtTextBox. I want the worker-thread to pass strings to the form, so that every string is displayed in the textbox.
Everytime a new string is generated in the worker thread I call an event, and this should now display the string.
But I don't know how to pass the string! This is what I tried so far:
///// Form1
private void btn_myClass_Click(object sender, EventArgs e)
{
myClass myObj = new myClass();
myObj.NewListEntry += myObj_NewListEntry;
Thread thrmyClass = new Thread(new ThreadStart(myObj.ThreadMethod));
thrmyClass.Start();
}
private void myObj_NewListEntry(Object objSender, EventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
// Here I want to add my string from the worker-thread to the textbox!
richTextBox1.Text += "TEXT"; // I want: richTextBox1.Text += myStringFromWorkerThread;
});
}
///// myClass (working thread...)
class myClass
{
public event EventHandler NewListEntry;
public void ThreadMethod()
{
DoSomething();
}
protected virtual void OnNewListEntry(EventArgs e)
{
EventHandler newListEntry = NewListEntry;
if (newListEntry != null)
{
newListEntry(this, e);
}
}
private void DoSomething()
{
///// Do some things and generate strings, such as "test"...
string test = "test";
// Here I want to pass the "test"-string! But how to do that??
OnNewListEntry(EventArgs.Empty); // I want: OnNewListEntry(test);
}
}
Like this
public class NewListEntryEventArgs : EventArgs
{
private readonly string test;
public NewListEntryEventArgs(string test)
{
this.test = test;
}
public string Test
{
get { return this.test; }
}
}
then you declare your class like this
class MyClass
{
public delegate void NewListEntryEventHandler(
object sender,
NewListEntryEventArgs args);
public event NewListEntryEventHandler NewListEntry;
protected virtual void OnNewListEntry(string test)
{
if (NewListEntry != null)
{
NewListEntry(this, new NewListEntryEventArgs(test));
}
}
}
and in the subscribing Form
private void btn_myClass_Click(object sender, EventArgs e)
{
MyClass myClass = new MyClass();
myClass.NewListEntry += NewListEntryEventHandler;
...
}
private void NewListEntryEventHandler(
object sender,
NewListEntryEventArgs e)
{
if (richTextBox1.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
this.NewListEntryEventHandler(sender, e);
});
return;
}
richTextBox1.Text += e.Test;
}
I've taken the liberty of making the NewListEntryEventArgs class immutable, since that makes sense. I've also partially corrected your naming conventions, simplified and corrected where expedient.
You need to create a new class by inheriting off EventArgs.
Create your own version of the EventArgs.
Do it like this:
public class MyEventArgs : EventArgs
{
public string MyEventString {get; set; }
public MyEventArgs(string myString)
{
this.MyEventString = myString;
}
}
Then in your code replace the EventArgs with MyEventArgs and create an MyEventArgs object with your string in it.
Then you can access it by using the MyEventArgs instance .MyEventString.
So you would do something like this:
///// myClass (working thread...)
class myClass
{
public event EventHandler NewListEntry;
public void ThreadMethod()
{
DoSomething();
}
protected virtual void OnNewListEntry(MyEventArgs e)
{
EventHandler newListEntry = NewListEntry;
if (newListEntry != null)
{
newListEntry(this, e);
}
}
private void DoSomething()
{
///// Do some things and generate strings, such as "test"...
string test = "test";
OnNewListEntry(new MyEventArgs(test));
}
}
And in your form:
private void myObj_NewListEntry(Object objSender, MyEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
// Here I want to add my string from the worker-thread to the textbox!
richTextBox1.Text += e.MyEventString;
});
}
In general you need to inherit EventArgs and add a string property, and then make your event of type EventHandler<YourEventArgs>, but that is a classic case for the BackgroundWorker.
Sample here:
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
and here:
C# backgroundWorker reports string?