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
Related
I'm trying to understand how WPF implements the routed commands which, internally, are themselves implemented by routed events. In the UIElement class definition, we find this piece of code:
EventManager.RegisterClassHandler(type, CommandDevice.CommandDeviceEvent, new
CommandDeviceEventHandler(UIElement.OnCommandDeviceThunk), false);
From there on, the UIElement.OnCommandDeviceThunk handler will pass along all the information through arguments of functions it calls in its body which themselves do the same until it reaches the CommandBinding.Executed event which we subscribe to, thus executing our response code.
What I can't seem to find, and would like to understand, is who raises the CommandDevice.CommandDeviceEvent?
When, for example, I have linked a ButtonBase subclass object's Command property to an ApplicationCommands command, does it raise the CommandDeviceEvent in some way and how does it do it?
I understand the GlobalEventManager holds scores of lists of event handlers, but I haven't yet understood who raises the events to trigger those handlers?
When, for example, I have linked a ButtonBase subclass object's Command property to an ApplicationCommands command, does it raise the CommandDeviceEvent in some way and how does it do it?
The ButtonBase class calls the ExecuteCommandSource method of an internal CommandHelpers class when it is clicked: https://referencesource.microsoft.com/#PresentationFramework/Framework/System/Windows/Controls/Primitives/ButtonBase.cs,c0949dd81fca07f3,references
This method then executes the actual command, i.e. the object that the ICommand property returns: https://referencesource.microsoft.com/#PresentationFramework/Framework/MS/Internal/Commands/CommandHelpers.cs,518e4547841e704d
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);.
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.
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).
Im struggling a bit with a design issue. Im making a very simple gui system in c#. The code is meant to be reusable so Im looking for the most flexible solution here. The solutions I come up with seem to all have their drawbacks.
For simplicity lets pretend there are three classes: controller, button and the client code. The client code is the code using the gui system. It creates the controller and calls Update() on it. The controller creates a bunch of button instances and calls Update() on them. The buttons draw themselves and check for mouse clicks.
Now the problem is how do I get the fact that a button was clicked to the client code?
Option 1: Add GetButton(string name) to the controller class. The client code can then subscribe to the events defined in the button class => GetButton("but").MouseUpEvent += MouseUpHandler; The drawback to this is that this exposes Button.Update() which is, and should only, be used by the controller.
Option 2: Have the controller subscribe to all buttons and the client code subscribe to the controller. The drawback here is more parsing code in the client code as now all events are funneled through the controller, so the client has to check which button sent each event. I prefer to setup the flow of events in the initialization phase like in option 1.
Option 3: Add Subscribe/Unsubscribe methods to the controller for each event (SubscribeMouseUp(string buttonName, GUIDelegate del) etc.) Drawback is the controller api grows quickly.
So right now Im leaning towards option 1, but GetButton returns an interface (IClientButton maybe) that only declares the events, thereby hiding Update() from the client, but Im not sure if this is how interfaces are supposed to be used.
Any insight is appreciated.
Bas
Presumably this is an issue because Update() is public?
Presuming you've organized your button and controller into the same namespace would using internal protection suit your needs?
interface can be used that way, INotifyPropertyChanged is an interace with 1 item which is an event.
what about using RoutedEvents?
There's a 4th, maybe more popular option.
Have a dispatcher as a central location to register/unregister with. All event receivers register a callback with the dispatcher. All event generators send their events to the dispatcher.
It keeps the API cleaner and helps to untangle object referencing.
In your Controller, add two events - ButtonCreated and ButtonDestroyed.
public event EventHandler<ClientButtonEventArgs> ButtonCreated;
public event EventHandler<ClientButtonEventArgs> ButtonDestroyed;
The ClientButtonEventArgs is simply an EventArgs wrapper around your IClientButton interface.
Have your client code subscribe to both of these events. When the Controller creates a new button, have it fire the ButtonCreated event. The client code can then subscribe to the necessary Button events when it receives the event notification. Similarly, the Controller will fire the ButtonDestroyed event as necessary, allowing the client code to unsubscribe from the Button's events.
In this way, the entire sequence is event-driven. The client code reacts to the creation and destruction of a Button, which it seems like is what you're after.