Handler fires to early - c#

I have an device with an integrated bixolon printer in it. I want to create an app to print on the printer. My OnCreate method looks as follow:
protected override void OnCreate(Bundle bundle){
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
printer = new BixolonPrinter(this, new MyHandler(), Looper.MainLooper);
printer.FindUsbPrinters();
//button connect
Button button = FindViewById<Button>(Resource.Id.buttonConnect);
button.Click += delegate {
printer.ConnectUsb();//in the brackets I would need the value of the Handler back once it is available
}; }
My Handler is as follow:
private class MyHandler : Handler
{
public override void HandleMessage(Message msg)
{
switch (msg.What)
{
case BixolonPrinter.MessageUsbDeviceSet:
Console.WriteLine("U S B device::: " + msg.Obj);
//can not return the msg.Obj back to the button event
break;
}
}
}
The problem is the once the instance of the BixolonPrinter is created it immediately fires the Handler. There is no way to bring back the result of the Handler to the button event. To make that problem a litte bit more complicated, the BixolonPrinter is a Java .jar file. So how can I get the result back to the event button?

When you use MainLooper, everything will be executed on main thread. Create HandlerThread for interaction instead. To postpone execution, use Handler.postDelayed() method, or, what is better, use RxJava library

Related

MS Band SDK - Button pressed event handler not being called

I've set up my tile and page layout with a button in my app but when I press the button the event handler does not get called. I tried with the tile open event handler but that doesn't work either. My code is as follows:
private async void OnConnectToBand()
{
IBandInfo[] pairedBands = await BandClientManager.Instance.GetBandsAsync();
try
{
using (IBandClient bandClient = await BandClientManager.Instance.ConnectAsync(pairedBands[0]))
{
//add tile, create page layout with button and add content with button
//subscribe to listeners
bandClient.TileManager.TileButtonPressed += EventHandler_TileButtonPressed;
// Start listening for events
bandClient.TileManager.StartReadingsAsync();
}
}
catch(BandException ex)
{
//handle a Band connection exception
}
}
void EventHandler_TileButtonPressed(object sender, BandTileEventArgs<IBandTileButtonPressedEvent> e)
{
// handle event
}
The tile and page get created fine but the button doesn't trigger the event handler. Any ideas why it's not being called?
UPDATE: I just went through my code and the SDK doco again and remembered I'm doing something different which is why it might not be working. The doco has the following for adding the button to the layout which doesn't compile:
// create the content to assign to the page
PageData pageContent = new PageData
(
pageGuid,
0, // index of our (only) layout
new Button(
TilePageElementId.Button_PushMe,
“Push Me!”)
);
The compiler says there isn't a constructor for Button that takes in 2 arguments.
I assumed there was an error in the sample code and changed it to TextButtonData which compiles fine but now I'm wondering if that is why the event handler isn't working? Code is:
PageData pageContent = new PageData(
pageGuid,
0, // index of our (only) layout
new TextButtonData(
(short)TilePageElementId.Button_PushMe, "Push"));
Any ideas?
This is great to see someone developing on the MS Band.... heres a few links that discuss the OnConnectToBand and its setup
void EventHandler_TileButtonPressed(object sender,
BandTileEventArgs<IBandTileButtonPressedEvent> e)
{
// This method is called when the user presses the
// button in our tile’s layout.
//
// e.TileEvent.TileId is the tile’s Guid.
// e.TileEvent.Timestamp is the DateTimeOffset of the event.
// e.TileEvent.PageId is the Guid of our page with the button.
// e.TileEvent.ElementId is the value assigned to the button
// in our layout (i.e.,
// TilePageElementId.Button_PushMe).
//
// handle the event
}
Section 9- Handling custom events
http://developer.microsoftband.com/Content/docs/Microsoft%20Band%20SDK.pdf
Talks about adding, clicking, removing tiles
http://www.jayway.com/2015/03/04/first-impression-of-microsoft-band-developing-2/
Try adding a dialog(below is windows code, for ios or android have a look at the above mentioned manual) to respond to the event (in your code above there is nothing in your event handler? this to see if it actually does something?
using Microsoft.Band.Notifications;
try
{
// send a dialog to the Band for one of our tiles
await bandClient.NotificationManager.ShowDialogAsync(tileGuid,
"Dialog title", "Dialog body");
}
catch (BandException ex)
{
// handle a Band connection exception
}
You can only receive events from the Band while you have an active IBandClient instance (i.e. an active connection to the Band). In your code above, the bandClient instance is disposed of immediately after StartReadingsAsync() is called, due to the use of the using() {} block. When an IBandClient instance is disposed, it causes the application to disconnect from the Band.
You need to hold onto the IBandClient instance for the length of time during which you wish to receive events, and dispose of the instance only after that time.

How to Capture 'Send' button event for Outlook using UI Automation in C#?

I want to capture 'Send' button event of outlook using UI Automation.
Right now i am able to get 'Focus Change Event' like whenever iam minimizing or maximizing the WINWORD window the the event is raised instead of that i want to get the event on Send button click.
private void SendButtonInvoke()
{
Process[] processes = Process.GetProcessesByName("WINWORD");
AutomationElement aeOutLook = null;
foreach (var item in processes)
{
aeOutLook = AutomationElement.FromHandle(item.MainWindowHandle);
}
//AutomationElement outlookelm = AutomationElement.FromHandle(processName.MainWindowHandle);
AutomationElement buttonAddInstance = aeOutLook.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "Send"));
if (buttonAddInstance == null)
{
MessageBox.Show("Add button instance not found");
}
else
{
AutomationPropertyChangedEventHandler ButtonEvent =
new AutomationPropertyChangedEventHandler(ButtonChecked_EventHandler);
//Attaching the EventHandler
Automation.AddAutomationPropertyChangedEventHandler(buttonAddInstance, TreeScope.Children,
ButtonEvent, AutomationElement.NameProperty);
}
}
private void ButtonChecked_EventHandler(object sender, AutomationEventArgs e)
{
AutomationElement ar = sender as AutomationElement;
MessageBox.Show("Button Clicked Sucessfully.");
}
You have to specifiy the EventHandler for the involved UIA Pattern. (For your case it's likely to be the InvokePattern):
Automation.AddAutomationEventHandler(InvokePattern.InvokedEvent, AutomationElement buttonAddInstance ,TreeScope.Element, new AutomationEventHandler(OnStartInvoke));
private static void OnStartInvoke(object src, AutomationEventArgs e)
{
//logic
}
I wrote and tested the code below and it seems to work for me.
private void AddEmailSendEvent()
{
// Find the new email window
PropertyCondition newEmailWindowCondition = new PropertyCondition(AutomationElement.NameProperty, "Untitled - Message (HTML) ");
AutomationElement NewEmailWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, newEmailWindowCondition);
// Find the Send Button
PropertyCondition sendEmailButtonCondition = new PropertyCondition(AutomationElement.NameProperty, "Send");
AutomationElement sendButton = NewEmailWindow.FindFirst(TreeScope.Descendants, sendEmailButtonCondition);
// If supported, add the invoke event
if (sendButton.GetSupportedPatterns().Any(p => p.Equals(InvokePattern.Pattern)))
Automation.AddAutomationEventHandler(InvokePattern.InvokedEvent, sendButton, TreeScope.Element, handler);
}
private void handler(object sender, AutomationEventArgs e)
{
// Do whatever is needed, for testing this just adds a message to my forms Main UI
AddMessage("Invoke event occured");
}
I should note that I'm using the .Net 4.0 automation libs. I've found the older ones don't always work the way I want them. I also tested this with Outlook 2013, and both outlook and the new email message were already open when I tested this. It doesn't handle waiting for them to appear.
Just so your aware, these events don't always work for all controls. Some custom controls are made in such a way the invoke events are not reported to the UI in a way the event can register. With that said, from my testing you should be able to use this method on the send button.
Invoking vs mouse clicks: Just to add a little more detail, the standard control causes the invoke event to fire when a user clicks it. "Invoke" is just the standard event fired on clickable controls. The only time a click wouldn't fire the same invoke is if the developer decided to intercept the click somehow and redirect it elsewhere. I've seen this a lot when people build there own custom controls.
If your not sure about whether a control using/firing the invoke event or not you can get use the Accessible Event Watcher to watch a control as you click it. You can get more information on the tool here: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317979(v=vs.85).aspx

How to make event calling holder class function

This may have been asked several times, but I don't know what to search for..
Anyway. I have a class called Character. Inside of it I want to have a collision component that I have called RectangleCollision. Inside of it there is a function called IsOverlapping that checks for overlap.
I want to have a function that can be modified for each game object. For example create a function called OnBeginOverlap(); that will fire everytime the collision component detects a collision.
Is there any way that I can bind this function as delegate or event? Or something?
You have to read about events and delegates. There are plenty of examples on the web. The easiest I managed to find when I was trying to understand the subject was this:
The Simplest C# Events Example Imaginable
You can also check out the below (you can compile this as console application):
class Character
{
public delegate void OverlappingHandler(Character character, EventArgs e);
public event OverlappingHandler OverlappingEvent;
public void IsOverlapping()
{
bool overlapping = true;
if (overlapping)
{
if (OverlappingEvent != null)
{
OverlappingEvent(this, null);
}
}
}
}
class Program
{
static void Main(string[] args)
{
Character c = new Character();
c.OverlappingEvent += OverlappingEventHandler;
c.OverlappingEvent += OverlappingSecondEventHandler;
c.IsOverlapping();
Console.Read();
}
static void OverlappingEventHandler(Character character, EventArgs e)
{
Console.WriteLine("We have overlapping here!!");
}
static void OverlappingSecondEventHandler(Character character, EventArgs e)
{
Console.WriteLine("Seriously, we have overlapping !!");
}
}
So step by step:
Create a delegate, which is a bridge between your event and the code you want to run when event is triggered. You give parameters to a delegate, which are (object sender, EventArgs e) - in this example sender is the Character class, arguments are used to send additional info - for example type of character.
Create event of our delegate type
In our function IsOverlapping() there would be your logic checking if there is overlapping happening. If there is, you fire up event. You should check first if there is anything connected to the event (hence the if (OverlappingEvent != null)) - if some there is something, fire up the event.
In the Main() you create an instance of the class and...
Subscribe your event handlers to it, so the code that should be executed when the event is triggered. I connected two methods, just to show that you can subscribe more than one.
Now when you run c.IsOverlapping() this is what happens:
your logic to check overlapping runs,
if there is overlapping, there will be a check if OverlappingEvent has code subscribed (it does in Main()),
if it does event will be triggered,
code subscribed to the event runs - in this case your code in Main().
You can compile this as console app and it will display 2 lines:
We have overlapping here!!
Seriously, we have overlapping !!
Hope this helps.

Update 2 different classes from a settings flyout?

As per MSDN guidelines we need to put all the app's settings into the SettingsPane and then the app should update all pages when the settings is applied.
In my app I need to have a reset option which brings the app to the default settings. There are 2 pages, Calendar.xaml and HistoryStatistics.xaml that i need to update when the reset button is pressed. All the data of the app is put in a singleton class called CycleManager. I have used a SettingsFlyout control from the Callisto Toolkit.
App.Xaml
Registered the settings in the App.xaml
SettingsPane.GetForCurrentView().CommandsRequested += OnCommandsRequested;
and in OnCommandsRequested function, created the reset handler
var reset = new SettingsCommand("reset", "Reset", (handler) =>
{
var settings = new SettingsFlyout();
settings.Content = new ResetUserControl();
settings.HeaderBrush = new SolidColorBrush(_background);
settings.Background = new SolidColorBrush(_background);
settings.HeaderText = "Reset";
settings.IsOpen = true;
});
args.Request.ApplicationCommands.Add(reset);
CycleManager.cs
In the CycleManager class, there is a m_Reset variable,its setter and getter and an event handler called ResetClicked
public event EventHandler ResetClicked;
public bool Reset
{
get
{
return m_reset;
}
set
{
m_reset = value;
if (ResetClicked != null)
ResetClicked(this, EventArgs.Empty);
}
}
Next is the part where i have associated this handler in my first class calendar.xaml
Calendar.xaml
In the constructor of the class I declare the event handler
CycleManager pCycMan = CycleManager.Instance;
pCycMan.ResetClicked += this.ResetClicked;
followed by the definition of the event handler
private async void ResetClicked(object sender, EventArgs e)
{
CycleManager pCycMan = CycleManager.Instance;
if (pCycMan.Reset == true)
{
try
{
await Windows.Storage.ApplicationData.Current.ClearAsync(Windows.Storage.ApplicationDataLocality.Local);
pCycMan.InitializeValues();
}
catch (Exception)
{
}
}
CreateCalendar();// UI is loaded
}
In the constructor of the HistoryStatistics.xaml I have done the same thing as above
HistoryStatistics.xaml
public HistoryStatistics()
{
CycleManager pCycMan = CycleManager.Instance;
pCycMan.ResetClicked += this.ResetClicked;
}
and defined
private void ResetClicked(object sender, EventArgs e)
{
CycleManager pCycMan = CycleManager.Instance;
if (pCycMan.Reset == true)
{
await Windows.Storage.ApplicationData.Current.ClearAsync(Windows.Storage.ApplicationDataLocality.Local);
pCycMan.InitializeValues();
LoadListView();// loads the UI
DisplayStatistics();//loads the UI for the page
}
}
Now the problem
Is this the right approach?
When Reset is pressed in the first from the second page(HistoryStatistcs), the reset clicked function declared in the first page(Calendar.xaml.cs) is called first and then the one in HistoryStatistics. And both gets executed async! :(
Is this a right behaviour?
This question is quite long. Hope everybody understood the scenario and question.
There is nothing wrong with the behaviour you outlined. Two pages subscribe to an event and event uses multi cast delegate which means they will both get fired.
I think you need a simpler behaviour here. Each xaml page should subscribe to that event on OnNavigatedTo and should unsubscribe in OnNavigatedFrom.
That way only one of the two actually executes the cleanup.
The complexity/confusion is likely coming because of not using the MVVM (model, view, and view model) separation. you may want to read about this. keeping the separation helps. Below are few pointers on this. but not necessarily a full design for your app.
in this example: CycleManager.Instance is kind of serving the model (the data). You may want to rename ResetClicked to SettingChanged and think of the event as notification for clients that one or more settings properties exposed has changed. It should also expose ResetSettings() method that can be called by ResetUserControl.
// model for the settings
class SettingsManager
{
public event EventHandler SettingsChanged;
public async void ResetSettings()
{
await Windows.Storage.ApplicationData.Current.ClearAsync
(Windows.Storage.ApplicationDataLocality.Local);
// initialize all values to default values;
this._intializeValues();
if (this.SettingsChanged != null)
this.SettingsChanged(this, EventArgs.Empty);
}
}
HistoryStatistics and Calendar class should have view model that should listen for SettingsChanged event and update the properties exposed. Each page view (xaml) binds to the properties exposed by the respective view model. This will require some refactoring of current code.
Without that, ResetClick eventhandlers can be changed to SettingChanged event handlers and take required action. They need not call setting mgr to initialize values.
class HistoryStatistics
{
private void SettingsChanged(object sender, EventArgs e)
{
SettingsManager settingsManager = SettingsManager.Instance;
LoadListView();// loads the UI
DisplayStatistics();//loads the UI for the page
}
}
HTH.

C# Onpaint is not firing

I have this code:
private void HandleGUI()
{
if (_currentForm == null)
{
navigationSideBar1.Visible = false;
pnlToolbar.Visible = false;
return;
}
if (_currentForm.ShowNavigationBar)
{
HandleNavigationButton(_currentForm);
}
btnSave.Visible = _currentForm.ShowSaveButton;
btnClose.Visible = _currentForm.ShowCloseButton;
btnSave.Paint += new PaintEventHandler(btnSave_Paint);
navigationSideBar1.Visible = _currentForm.ShowNavigationBar;
pnlToolbar.Visible = _currentForm.ShowToolBar;
btnSave.Refresh();
btnSave.Invalidate();
}
I am registered on the onpaint event of the save button (btnSave), but this event is not fired, even when I call Refresh or Invalidate. How is this possible?
EDIT:
This is how the saave button class looks like:
public class SaveButton : ButtonX
{
public SaveButton()
{
this.Image = Properties.Resources.Save;
this.Text = "Opslaan";
this.Size = new Size(108, 39);
}
}
Try adding a regular DevComponent button (i.e. not a subclass of it) to a test form and see if it ever fires its Paint event. They may have exposed a Paint event (so that their interface matches that of a regular button) but not actually implemented it.
Setting userpaint to true will fire the onpaint event
this.SetStyle(ControlStyles.UserPaint, true);
From MSDN:
Calling the Invalidate method does not force a synchronous paint; to force a synchronous paint, call the Update method after calling the Invalidate method.
So, you need an Update call. Now, Refresh is just Invalidate w/ update children + Update, so theoretically you're taken care of. All I can think is that Windows doesn't call Paint unless it really needs to, ie when the form is shown on the UI or written to a graphics device ("screenshot" of an invisible window). Are either of these the case?
It looks like you're not calling the base class constructor in the constructor of your SaveButton component.
public class SaveButton : ButtonX
{
public SaveButton() : base()
...

Categories

Resources