What is involved in adding my own event to WPF controls? - c#

I'm constantly having to use TouchDown/TouchUp events here in my WPF project to detect a 'double-tap'; sometimes on a listbox, sometimes a button, sometimes a telerik control. How would I go about adding a DoubleTap event and event handler to these controls? Too big of a job?

You could create a class that is constructed with a reference to the control and a delegate function. (Please forgive my not perfect syntax [if it isn't perfect], I am typing this from memory)
public class DoubleTap {
delegate void ActionFunction();
Control ReferencedControl;
public DoubleTap ( ref Control referencedControl , delegate actionFunction ) {
ActionFunction = actionFunction;
ReferencedControl = referencedControl;
// apply TouchDown and TouchUp event handlers to ReferencedControl
}
// Put your TouchDown and TouchUp functions for testing the double tap here
// when double tap tests as true then call ActionFunction();
}

You will have to use behaviors for this.This will include creating derived type from System.Windows.Interactivity.Behavior and override OnAttached method for TouchDown/TouchUp.
See WPF Tutorial | Behaviors and Introduction to Attached Behaviors in WPF for how to implement behaviors.

Related

Can i know in the parent Form if an inherited Form has subscribed to the Show event?

I have the following forms in my winforms framework
FormBase (inherited from Form)
FormBaseList (inherited from FormBase)
FormBaseDetail (inherited from FormBase)
Now every form in the application inherits from on one of the 3 above.
For example FormCustomerList will be inherited from FormBaseList
Now in FormBaseList the event FormBaseList_Shown is present (by doubleclicking on it in the properties window in VS)
What I would like to know in the code from FormBaseList_Show is if there is an event FormCustomerList_Show present (again by doubleclick on it in the properties window).
Is that even possible ?
So why do I want this ?
Because some changes in the framework require the forms to not use the Shown event anymore but a custom event.
I would like to catch and show a warning to the developer if he adds a Show event to a form, and if it is really needed he can set a property that will hide this warning.
This warning does not needs to be shown at designtime, at runtime would be enough. But if its possible at designtime that would be a bonus.
So can this be done and is there maybe a better way to do this ?
I hope this explanation is clear
EDIT
The idea is that when a developer makes use of a Show event he must get a warning (either at designtime or runtime). If he feels that he really needs the Show method he should be able to set the warning off for this particular form
To throw exception or show a message box at run-time you have the following options:
Shadow the Shown event and in the add part, throw an exception (unless the skip flag has been set).
Using reflection find the event handler list for Shown event and check if there is a handler attached to the event.
In both solutions, a boolean property can be used to override the behavior in derived forms.
Option 1 - Shadowing Shown event and add the code to add
You can shadow the Shown event and in the add accessor, add a code to show a message box or throw exception if a handler added to the event.
In the following example, I've added ThrowExceptionOnSubscribingShownEvent property to the base form which is true by default which means it throws the exception on subscribing the Shown event.
public bool ThorwExceptionOnSubscribingShownEvent { get; set; } = true;
public new event EventHandler Shown
{
add
{
if (ThorwExceptionOnSubscribingShownEvent)
throw new InvalidOperationException("Shown event is deprecated.");
base.Shown += value;
}
remove
{
base.Shown -= value;
}
}
Option 2 - Finding event handler list for Shown event
As an option for run-time, you can override OnShown method and using reflection, get EVENT_SHOWN field and using it, get the event handler list of Shown event. Then you can check if the event handler list is not empty, throw an exception.
In the following example, I've added ThrowExceptionOnSubscribingShownEvent property to the base form which is true by default which means it throws the exception on subscribing the Shown event. You can set it to false when needed in derived forms:
public partial class BaseForm : Form
{
public BaseForm()
{
InitializeComponent();
}
public bool ThrowExceptionOnSubscribingShownEvent { get; set; } = true;
protected override void OnShown(EventArgs e)
{
if (!DesignMode)
{
var EVENT_SHOWN = typeof(Form).GetField("EVENT_SHOWN",
BindingFlags.NonPublic | BindingFlags.Static)
.GetValue(null);
var handlers = Events[EVENT_SHOWN]?.GetInvocationList();
if (ThrowExceptionOnSubscribingShownEvent && handlers?.Length > 0)
throw new InvalidOperationException("Shown event is deprecated.");
}
base.OnShown(e);
}
}
You should shadow the Shown event and deprecate it this way:
[Obsolete("Shown event is deprecated.")]
public new event EventHandler Shown
{
add { base.Shown += value; }
remove { base.Shown -= value; }
}
You have marked it as obsolete and it will show a warning in Error List window at compile time when you build your solution.
Also the event will keep working as expected by subscribing to the original Shown event of the base.
To disable the warning, add the following line of code at top of designer.cs file of the form which has subscribed to the event:
#pragma warning disable CS0618 // Type or member is obsolete
and add this line to bottom:
#pragma warning restore CS0618 // Type or member is obsolete
Note: In the other files, except designer.cs file, it's enough to surround just the event handler subscription by #pragma. But for designer.cs, you cannot surround event handler subscription, because by changing anything in designer, the content of InitializeComponent and the block of code which is defining member variables will be auto-generated and all your manual changes in designer.cs will be lost. But if you put #pragma at top and bottom of the file, it's safe and will not be removed from designer.cs.
It's probably possible using reflection, but it would be rather messy. A better tactic would be to hide the Shown event like this:
[Obsolete("Don't use this event, use my custom one")]
public new event EventHandler Shown;
Then anything that tries to use this event will generate compiler warnings.

Xamarin Forms Event Bubbling and Invoking Operations on a Custom Renderer

I am creating a custom Xamarin Forms control that contains three buttons (1,2,3) inside a view. Let's just call it a GaugeView for the sake of this example. Here is how it is currently setup:
The GuageView has a custom renderer on both iOS and Android called GuageViewRenderer.
The GuageView exposes event handlers for Clicked1, Clicked2, and Clicked3.
The GuageView exposes ICommand properties for Click1, Click2, and Click3.
The problem is, I need to fire the event handlers from the custom renderer because only the native platform control knows when one of the buttons has been pressed. How do you bubble the events back up to the GuageView, which is where the shared code lives?
I was planning to wire up the commands and the event handlers down inside the custom renderer, but I'm having a heck of a time with it since events can only be fired from within the original class (GuageView).
Is there a better way to structure this? The main thing I am trying to do is expose the platform native guage and wire its buttons up so the event handlers in the shared code (GuageView) gets the event firings.
Right, you can't raise events outside of the class that declares them. So you'll have to add a method to GaugeView that will raise the events. I would also have that same method invoke the commands as well. So in GaugeView
public void RaiseClick1() {
var clicked1 = Clicked1;
if (clicked1 != null)
clicked1(this, EventArgs.Empty);
if (Command1 != null && Command1.CanExecute(Command1Paramter))
Command1.Execute(Command1Parameter);
}
Then in GaugeViewRender whenever you need to notify the view that a button was clicked:
Element.RaiseClick1();
Late answer but maybe for the future: You can raise the click event of a button from outside using the IButtonController interface.
The Xamarin.Forms.Button class implements this interface which provides one single method: SendClicked
By casting your Xamarin.Forms element in the renderer (this.Element) to IButtonController you're able to call this method and raise the clicked event of the Xamarin.Forms.Button.
I also created a blog post about this topic: http://software.fauland.cc/?p=5637

Custom events in Expression Blend

I am developing my own FTP client and I want to create a nice GUI using expression blend. I was wondering how to create a custom event so that I can trigger an animation when an upload completes. In other words, is there a way I can subscribe to an even in expression blend/ create my own event? Thanks for the help.
Just put a new public property called bool DownloadCompleted { get; set; } in your ViewModel, and then use a ControlStoryboardAction with a DataTrigger to watch for a change in the DownloadCompleted property to true ... the animation will then be started.
There's a good explanation how to do it here.
http://www.basarat.com/2011/05/expression-blend-starting-storyboard.html
http://www.silverlightbuzz.com/2009/10/12/animating-with-storyboards-in-blend/
There's no need to create your own Event to notify of the completed download, however, you can do that if you wish...just choose an EventTrigger instead...and point the SourceName to the named element that's in your XAML that either has the event raised on it or (if it's a bubbling event, then you have the flexibility of watching the event on other elements....as long as the event bubbles through them).

Adding custom UI behavior to controls via a Component

In my project, I have several controls that display a set of points on the screen. I would like to provide "lasso selection" functionality for all of these controls. To do this, I wrote a class called "Lasso", which takes care of tracking mouse movements, displaying the lasso, raising an event when the lasso is closed, etc. So far so good. But, in order to use the lasso, I must write code like this:
public partial class MyControl : UserControl {
private Lasso lasso;
public MyControl() {
InitializeComponent();
lasso = new Lasso();
lasso.HookEvents(this);
}
}
The "lasso.HookEvents" method takes care of hooking up the lasso to the mouse events for the host control.
What I would like to do is somehow provide a way for people to simply drag the "Lasso" component from the Toolbox onto their UserControl or Form at design time, and not worry about writing any code themselves; the lasso should magically "just work". Is there a way to do that ? I tried extending my Lasso class from Component, but I couldn't figure out how to get the Designer to generate the "lasso.HookEvents(this)" invocation automatically.
If possible, just capture the mouse events in the Lasso object. If that's not possible or doesn't work: In your Lasso class, add a handler to the Loaded event, and in the handler run this.HookEvents(this.Parent);.

Raise custom events in C# WinForms

I have some Events I created on my own and was wondering on how to raise them when I want.
Probably my application design is also messed up, might take a look at that if you like.
This is the Structure
ProgramContext
- Form MainWindow
+ Control TextBox
+ Control Button
+ ...
In this case, the MainWindow.TextBox holds some information that is updated quite often at runtime. So, I somehow need it to refresh itself when I want to (so it can reload its data from the database, where the it's stored)
I tried hooking an EventHandler to its Validating-Event, but that didn't seem to do the trick.
So, basically I have a method that reloads the data in ProgramContext
DataTable table = _adapter.GetData();
foreach (DataRow row in table.Rows)
{
MainWindow.TextBox.Text += table.Text.ToString();
}
That needs to be done whenever another method (that writes new data into table) is executed.
Any ideas?
Edit : It seems your question is more about hooking into a specific event, but FWIW below is how to fire custom events in general.
Handling the TextBox Changed Event
From what I understand, you want an external party to monitor events raised from a textbox on a Form and then to reload data on another form?
A quick and dirty would be to make the Form TextBox public and then others could subscribe to this event
MainForm.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
OR, in more recent versions of C#:
MainForm.textBox1.TextChanged += this.textBox1_TextChanged;
Adding Your own Custom Event
Another, cleaner way would be to raise a custom event, - e.g. MyDataChangedEvent below. This will allow you to abstract away the fact that the changes are coming from a textbox at all.
// Assuming you need a custom signature for your event. If not, use an existing standard event delegate
public delegate void myDataChangedDelegate(object sender, YourCustomArgsHere args);
// Expose the event off your component
public event myDataChangedDelegate MyDataChangedEvent;
// And to raise it
var eventSubscribers = MyDataChangedEvent;
if (eventSubscribers != null)
{
eventSubscribers(this, myCustomArgsHere);
}
You might also look at the Ent Lib Composite Application Block and Smart Client Software Factory - this has a very flexible event broking / pub sub mechanism for synchronising across UI "SmartParts" (controls, forms dialogs etc) in a loose-coupled fashion. (CAB is now very dated).

Categories

Resources