I need to inherit for ComboBox in order to add a new event OnSelectedValueChanging().
This event should be triggered when the user is attempting to change the current selected value of the combo box.
This event also should be cancellable (the user has the ability to use e.cancel as in the FormClosing event for example)
public class SUIComboBox : UIComboBox
{
/// <summary>
/// The prevously selected value
/// </summary>
private object _PreviousSelectedValue = null;
public event EventHandler<EventArgs> SelectedValueChanging;
protected virtual void OnSelectedValueChanging(object sender, CancelEventArgs e)
{
var handler = SelectedValueChanging;
handler?.Invoke(sender, e);
}
}
public class SelectedValueChangingEventArgs : CancelEventArgs
{
}
Related
I've got a user control that represents an employee. The xaml is an image of a character icon and there is a textbox for the employee name.
When text is typed into the textbox the Textchanged event is raised and this event handler is called:
private void employeeNameChangedEventHandler(object sender, TextChangedEventArgs args)
{
_employeeName = employeeName.Text;
}
The is a property in the user control so the name can be retrieved:
public string EmployeeName
{
get { return _employeeName; }
}
In MainWindow.xaml.cs I want to listen to the TextChanged eventhandler in the user control.
I've read up about delegates and have a bit of experience with events from Unity but just not sure the best way to implement this in wpf.
Ta
You can use customer routed event.
In your Usercontrol, you need add your routed event, like this:
public static readonly RoutedEvent NameChangedEvent = EventManager.RegisterRoutedEvent
("NameChanged", RoutingStrategy.Bubble, typeof(EventHandler<RoutedEventArgs>), typeof(UserControl1));
public event RoutedEventHandler NameChanged
{
add { this.AddHandler(NameChangedEvent, value); }
remove { this.RemoveHandler(NameChangedEvent, value); }
}
And In your textchanged event of textbox, you should raise your customer routed event.
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
this.RaiseEvent(new RoutedEventArgs(UserControl1.NameChangedEvent));
}
Now you just need add subscribe your customer routed event where you need your usercontrol as you do use textchanged.
<local:UserControl1 x:Name="uc" NameChanged="NameChanged"/>
And the NameChanged is like this
private void NameChanged(object sender, RoutedEventArgs e)
{
//when you input one character in you usercontrol, you will get here
}
I am new to events and have been trying to create one and succeed but I have one question.
I have created event like this:
public class CustomControl : Panel
{
public event EventHandler OutputChanged; //My event
public CustomControl()
{
InitializeComponents();
}
//This event raises inside richtextbox which is inside my panel
private void OnTextChanged(object sender, EventArgs e)
{
if (OutputUpdate == OutputUpdate.OnTextChanged)
{
ValidateText();
//This is my created event
OnOutputChanged(new OutputChangedEventArgs { Asd = "Something" });
}
}
//void for this event
protected virtual void OnOutputChanged(OutputChangedEventArgs e)
{
EventHandler handler = OutputChanged;
if(handler != null)
{
handler(this, e);
}
}
}
//Custom event args class for my event
public class OutputChangedEventArgs : EventArgs
{
public string Asd { get; set; }
}
Above code shows declaration of my event with custom class for EventArgs parameter and now I will show you how I implement it in my code:
customControl1.OutputChanged += OnOutputChanged;
private void OnOutputChanged(object sender, EventArgs e)
{
OutputChangedEventArgs args = e as OutputChangedEventArgs;
MessageBox.Show(args.Asd);
}
As you can see in my implantation I pass EventArgs and then I convert it to OutputChangedEventArgs and reason for that is because if I try private void OnOutputChanged(object sender, OutputChangedEventArgs e) I get error No overload for 'OnOutputChanged' matches delegate 'EventHandler'
So my question is how can I directly pass my custom EventArgs class so I do not need to convert it inside method that handles it?
You can use the generic version of EventHandler that allows the specification of the argument type.
public event EventHandler<OutputChangedEventArgs> OutputChanged;
I have a WinForms application wherein I have my main application with a separate class that is part of the solution. In the class which is defining a User control with Dev Express buttons, I have defined my event delegate, event, method and eventargs.
In the main program, i have defined my listener.
I am getting a null value in my event method and cannot see why. I have reviewed this a number of times and as far as I can see, it is completely correct.
I would appreciate any comments/corrections that would be useful here.
This is the code in my class.
public partial class XtraUserControl1 : XtraUserControl, IAnyControlEdit
{
public delegate void ButtonClickedEventHandler(object sender, ClickEventArgs e);
public event ButtonClickedEventHandler ButtonClicked;
public XtraUserControl1()
{
InitializeComponent();
}
public void OnButtonClicked(ClickEventArgs e)
{
if (ButtonClicked != null)
{
ButtonClicked(this, e);
}
}
public class ClickEventArgs : EventArgs
{
public readonly SimpleButton buttonClicked;
public ClickEventArgs(SimpleButton button)
{
this.buttonClicked = button;
}
}
This is the main code where I have defined the listener.
private void frmEHHeaders_Load(object sender, EventArgs e)
{
// Create the button group from the User Control XtraUserControl1 and add it to the grid repository
btnGroup = new User_Controls.XtraUserControl1();
RepositoryItemAnyControl riAny = new RepositoryItemAnyControl();
riAny.Control = btnGroup;
grdEHHeaders.RepositoryItems.Add(riAny);
colButtons.ColumnEdit = riAny;
// Add event handlers
this.grdEHHeaders.Views[0].MouseDown += gridView1_MouseDown;
gridView1.CustomRowCellEdit += GridView1_CustomRowCellEdit;
// Listener for the button class
btnGroup.ButtonClicked += new User_Controls.XtraUserControl1.ButtonClickedEventHandler(btnGroup_ButtonClicked);
GetData();
}
private void btnGroup_ButtonClicked(object sender, User_Controls.XtraUserControl1.ClickEventArgs e )
{
SimpleButton myButton = e.buttonClicked;
MessageBox.Show("You clicked " + myButton.Text);
}
I am trying to raise a event in one of classes of userControl, and Fire it in the Main class. I tried two different ways to fire this event, one of them works, But I still want to know why other way cannot work, and how to fix it.
My userContol class:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
return;
}
Class1 c = new Class1();
Thread accept = new Thread(
() =>
{
c.connection();
}
);
accept.Start();
}
}
And the Class1:
public class Class1
{
public delegate void myhandler(object sender, EventArgs e);
public event myhandler test;
public Class1()
{
}
public void connection()
{
test(this, new EventArgs());
}
}
In the Main, I just simply add into referent, and add
xmlns:my="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
then I try to subscribe this event in the main
public partial class SurfaceWindow1 : SurfaceWindow
{
/// <summary>
/// Default constructor.
/// </summary>
public SurfaceWindow1()
{
InitializeComponent();
Class1 c = new Class1();
c.test+=new Class1.myhandler(c_test);
// Add handlers for window availability events
AddWindowAvailabilityHandlers();
}
public void c_test(object sender, EventArgs e)
{
MessageBox.Show("fire");
}
}
If I only raise this event not into thread, it works fine, but If I try to let it raise in this thread, this test event only return null, and shows:
Object reference not set to an instance of an object.
looks like I did not subscribe it ever. So How to fix it if I must use it in thread.
This is a good example of what you really shouldn't be doing. You are trying to subscribe to an event of a class that is "owned" by another class. You are basically digging through the type hierarchy to find the event you want. This goes against good design.
Especially in UI applications there is a design concept called Event Bubbling. The type that owns the original object raising the event handles that event. In the handling of that event, it raises its own duplicate event. Here is a short-ish program that shows the concept:
public class RootEventClass
{
public event EventHandler SomeKindOfEvent;
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
Console.WriteLine("Root Event Firing");
OnSomeKindOfEvent(this, EventArgs.Empty);
}
}
public class FirstOwnerClass
{
private RootEventClass _rootClass;
public event EventHandler SomeKindOfEvent;
public FirstOwnerClass()
{
_rootClass = new RootEventClass();
_rootClass.SomeKindOfEvent += _rootClass_SomeKindOfEvent;
}
void _rootClass_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("First Owner Class Handling Root Owner Event");
OnSomeKindOfEvent(this, e);
}
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
_rootClass.RaiseEvent();
}
}
public class SecondOwnerClass
{
private FirstOwnerClass _firstClass;
public event EventHandler SomeKindOfEvent;
public SecondOwnerClass()
{
_firstClass = new FirstOwnerClass();
_firstClass.SomeKindOfEvent +=_firstClass_SomeKindOfEvent;
}
void _firstClass_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("Second Owner Class Handling First Owner Event");
OnSomeKindOfEvent(this, e);
}
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
_firstClass.RaiseEvent();
}
}
public class Program
{
public static void Main(string[] args)
{
SecondOwnerClass secondOwner = new SecondOwnerClass();
secondOwner.SomeKindOfEvent += secondOwner_SomeKindOfEvent;
secondOwner.RaiseEvent();
Console.ReadKey(true);
}
static void secondOwner_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("Got an event from the second owner defined in main");
}
}
If you run this program, you will get the following output:
Root Event Firing
First Owner Class Handling Root Owner Event
Second Owner Class Handling First Owner Event
Got an event from the second owner defined in main
So what is happening here. The Main method defines a SecondOwner object and then tells it to raise an event, which just passes it up the ownership chain to the root object. The magic is the event bubbling. The event is intercepted by each owning class and passed on. This way it can decide to pass it on or not.
Also, the Main method only needs to know about the events created in the SecondOwner class, it doesn't have to dig through SecondOwner, FirstOwner and finally RootEventClass.
Its an easy concept to grasp really, don't force your users (or yourself) to dig through types and ownership to get to an event, if users of the class will need that event, duplicate the event and bubble it.
Here is my class with event handler:
public delegate void MyKeyEventHandler(object sender, KeyEventArgs e);
public class KeyEvent
{
public event MyKeyEventHandler keyEvent;
public string key = "";
protected virtual void KeyPressed(KeyEventArgs e)
{
MyKeyEventHandler handler = keyEvent;
if (handler != null)
handler(this, e);
}
public KeyEvent()
{
keyEvent += new MyKeyEventHandler(keyPressed);
}
private void keyPressed(object sender, KeyEventArgs e)
{
key = e.KeyCode.ToString();
}
}
And in my Form1 I have this code: (EDITED)
KeyEvent ke = new KeyEvent();
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(ke.key);
}
When I run form and press key on keyboard and then click on button it pop up empty MessageBox. What I want is everytime I press a key on keyboard a MessageBox to pop up and show me which key I pressed. This code is just for testing, I don't want just to pop up message box, I need the key for other things.
Note: To handle the events on Form1 is not a solution, I need to handle the events in class. I making a libray.
It will not be possible for you to create a class that is capable of just automatically listening for events generated by its parent. How would that work? What would happen if you created a new KeyEvent class using something that wasn't a Form and didn't raise events?
You are going to need to give your KeyEvent class a reference to whatever thing that you want to monitor key events for. I realize that your intention is to create some third-party library, so you'd like to keep things as generic as possible in order to maximize its reuse. Since you are dependent on the KeyDown event, using Control is the most generic you can be. This is because it is where the KeyDown event is actually defined.
Let me show you what I mean...
1) Modify the constructor of your KeyEvent class to accept an instance of Control
public class KeyEvent
{
// You don't need to declare an internal event
public string key = "";
private Control _control;
public KeyEvent(Control control)
{
// Here is where we save the reference of Control that was passed to the class.
// This will enable you to access the instance of the Form or whatever else
// you want to use, which is helpful for unregistering events during cleanup
_control = control;
// Wire up your event handler to this SPECIFIC instance of Control.
// This will cause your `keyPressed` method to execute whenever
// the control raises the KeyDown event. All of the middleman
// event handling you are doing is unnecessary.
_control.KeyDown += keyPressed;
}
private void keyPressed(object sender, KeyEventArgs e)
{
key = e.KeyCode.ToString();
}
}
2) Modify the parent in which you are creating this KeyEvent to pass itself into the KeyEvent
// Now you pass 'this' into the constructor. This can be a Form, or any other
// Winforms control that may inherit from Control (which is all of them)
KeyEvent ke = new KeyEvent(this);
private void button1_Click(object sender, EventArgs e)
{
// At this point, ke.Key will always display the last
// key pressed in the Form when the button is clicked.
MessageBox.Show(ke.key);
}
You can do something like this:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 f = new Form1();
f.KeyPreview = true;
f.KeyDown += f_KeyDown;
Application.Run(f);
}
static void f_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show(e.KeyValue.ToString());
}
}
If you enable KeyPreview you will receive all keyDowns even of the controls placed on the Form. If you set it to false you only get the KeyDown when the Form has focus.
As you can see in the code you can connect any KeyDownEventHandler method in any class to the Form.
As there where questions left:
public class FormKeyListener
{
private Form formToListen = null;
public void SetFormToListen(Form form)
{
if (formToListen != null)
formToListen.KeyDown -= formToListen_KeyDown; // Unregister from old form if present
formToListen = form;
formToListen.KeyDown += formToListen_KeyDown; // Attach to new form
}
void formToListen_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show(e.KeyValue.ToString());
}
}
Which can be call this way somewhere in your code:
FormKeyListener fkl = new FormKeyListener();
Form1 f = new Form1();
f.KeyPreview = true;
fkl.SetFormToListen(f);