I want to add a media player control to SystemMediaControls. But, I have an issue here. When you pressed it, it occurs twice. Please see code below:
using Windows.Media;
using . . .
public class Main{
public static SystemMediaTransportControls systemMediaControls;
public Main(){
this.InitializeComponent();
systemMediaControls = SystemMediaTransportControls.GetForCurrentView();
int num = 0;
systemMediaControls.ButtonPressed += async (SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs e) =>
{
num++;
Debug.WriteLine($"Event number: {num}");
};
}
}
I proved it with debug logs, and the debug logs are:
Event number: 1
Event number: 1
Event number: 2
Event number: 2
Event number: 3
Event number: 3
I have no idea where's the problem is.
This is my fault. I put event on MainPage main function. The mistake is, I call MainPage more than once in the App.cs. For example:
void LaunchApp() {
new MainPage();
...
rootFrame.Navigate(typeof(MainPage));
}
So it initializes twice. That's why the event also fires twice. I have resolved my issue.
SystemMediaControls.ButtonPressed event fires twice
I have tested with official code sample here. Unfortunately, we can't reproduce this problem, Derive official tutorial, if you want to custom SystemMediaTransportControls, we need to sync playback status To MediaPlayerState at fist. and control the media player in button pressed event.
switch (mediaPlayer.PlaybackSession.PlaybackState)
{
case MediaPlaybackState.None:
systemMediaControls.PlaybackStatus = MediaPlaybackStatus.Closed;
break;
case MediaPlaybackState.Opening:
// This state is when new media is being loaded to the MediaPlayer [ie.
// Source]. For this sample the design is to maintain the previous playing/pause
// state before the new media is being loaded. So we'll leave the PlaybackStatus alone
// during loading. This keeps the system UI from flickering between displaying a "Play"
// vs "Pause" software button during the transition to a new media item.
break;
case MediaPlaybackState.Buffering:
// No updates in MediaPlaybackStatus necessary--buffering is just
// a transitional state where the system is still working to get
// media to start or to continue playing.
break;
case MediaPlaybackState.Paused:
if (mediaPlayer.PlaybackSession.Position == TimeSpan.Zero)
systemMediaControls.PlaybackStatus = MediaPlaybackStatus.Stopped;
else
systemMediaControls.PlaybackStatus = MediaPlaybackStatus.Paused;
break;
case MediaPlaybackState.Playing:
systemMediaControls.PlaybackStatus = MediaPlaybackStatus.Playing;
break;
}
For more detail please refer Manual control of the System Media Transport Controls
Related
As we know, if we press the F8(Play) keyboard button, iTunes or Music .app opened in default on macOS. Some Swift classes are available for preventing this keyboard shortcut but they are not compatible with C# & Xamarin. Fore example, Spotify macOS app have this ability. If you press play button on UI once, it takes the control over iTunes and handles the "Play" button key event.
I have this code block. However, macOS cannot fires the code block because of iTunes. The other keys like letters and numbers working correctly:
private NSEvent KeyboardEventHandler(NSEvent theEvent)
{
ushort keyCode = theEvent.KeyCode;
if(keyCode== 100) //rbKeyF8 100 is play button.
{
switch (isplaying)
{
case true:
StopMusic();
break;
case false:
PlayMusic();
break;
}
}
// NSAlert a = new NSAlert()
//{
// AlertStyle = NSAlertStyle.Informational,
// InformativeText = "You press the " + keyCode + " button :)",
// MessageText = "Hi"
//};
//a.RunModal();
return theEvent;
}
How can we do it with C# ? Thanks.
Answer is:
Register a new subclass
[Register ("App")]
public class App : NSApplication
{
public App (System.IntPtr p) : base (p)
{
}
public override void SendEvent (NSEvent theEvent)
{
base.SendEvent (theEvent);
}
}
In Info.plist change the PrincipalClass
<key>NSPrincipalClass</key>
<string>App</string>
And need to subclass NSApplication and look at sendEvent. You should convert Swift code to C#. Related swift code is here:
Make my Cocoa app respond to the keyboard play/pause key?
Now, i have another problem. Yep, this code block solved my problem’s
first part. Now my app responds the play button press. However, iTunes
opened after the my app's respond. How can I prevent it to open ?
The following code is giving me a small issue.
public void ButtonShort()
{
lcd.WriteLine(" K ");
GpioPinValue Readbutton = ButtonS.Read();
if (buttonS == GpioPinValue.Low)
{
Temp = Temp + "K";
}
}
Temp is a list which is empty by default. So every button press should add ONE 'K'.
But it actually registers 'K' multiple times.
What I want is that one button press only registers one 'K'.
Thanks for the help!
I can't directly help you for C#, but had a similar problem once where I used Java with the Pi4J Lib for the GPIO Access.
In there, you have events which are triggered by a changing input pin value. I catched that event and checked in the routine wether the state was high/low, depending on what had to be the actual trigger for counting.
Code in Java was quite straigt forward:
public void handleGpioPinInputStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
if (event.getState() == PinState.HIGH) {
[...]
}
}
[Edit - got interested... :-)]
Perhaps the following code from here will help:
private void buttonPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
// toggle the state of the LED every time the button is pressed
if (e.Edge == GpioPinEdge.FallingEdge)
{
ledPinValue = (ledPinValue == GpioPinValue.Low) ?
GpioPinValue.High : GpioPinValue.Low;
ledPin.Write(ledPinValue);
}
[...]
I am facing a major problem for custom touch event handling.
The goal is to route the touch event to different controls, depending on how many fingers are used.
For example:
We have a scrollview with many webviews arranged in it.
The zoomfactor is set to present one webview to fullscreen.
Currently I am using the pointer pressed / released functions like this, to configure the controls, so the event will be catched by the right one:
int pointerCount = 0;
private void ScrollView_PointerPressed(object sender, PointerRoutedEventArgs e)
{
try
{
pointerCount++;
if (pointerCount > 3)
pointerCount = 0;
switch (pointerCount)
{
case 1:
// I don't do anything, so it goes to the webview anyway
break;
case 2:
EnableScrolling();
break;
case 3:
ZoomInOut();
break;
default:
return;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
private void EnableScrolling()
{
ScrollViewer.ZoomMode = ZoomMode.Enabled;
ScrollViewer.VerticalScrollMode = ScrollMode.Enabled;
ScrollViewer.HorizontalScrollMode = ScrollMode.Enabled;
}
1-finger events should go to the webview // this works
2-finger events should go to the ScrollView // this is not working, because the webview grabs the touch event and will not release it again
3-finger events should zoom out // this works
The PointerPressed is always called, but the PointerReleased is not called when the PointerPressed was on the webview.
This also results in the effect of not decreasing the pointerCount, so it is possible to do a 1-finger tap 3 times and it results in the 3-finger event and zooms out, that should not happen.
Hopefully you can see the problem and help to resolve it.
If you think this is a way too wrong approach, feel free to show an alternative that works out better.
Well, I couldn't find a proper solution, but I was able to remove the unwanted side effect with upcounting the pointers event if they were released.
private void ScrollViewer_PointerReleased(object sender, PointerRoutedEventArgs e)
{
pointerCount = 0;
}
So the right direction handling is working fine now, but I still can't do something like:
currentWebView.CapturePointer(e.Pointer);
Because it won't root the pointerEvent into it's content, it will call the pointer events of the WebView, but it won't root it into it's html & js content.
I also tried to use
.... wb.ManipulationStarted += Wb_ManipulationStarted; ....
private void Wb_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
// something here
}
but this also will not arrive in the content.
Any ideas for another approach?
I figured out how to handle that, and it is so simple that I could cry...
I just added this line of code to tell the webviews js that there was a event...
await webView.InvokeScriptAsync("eval", new string[] { "document.elementFromPoint(" + pointX + ", " + pointY + ").click();" });
And the webview handles the rest of it. So there is no custom invoke as I was worried about, it's just the standard function invoked, that is always invoked when a touch/click is performed.
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.
I have a situation where I have to manage the button click event outside MainPage class (suppose in Class B). Here is the code that I'm using:
namespace TEST
{
public partial class MainPage: UserControl
{
public event Action simpleEvent;
public MainPage()
{
}
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
switch (comboBox1.SelectedItem as string)
{
case "UInt8":
B obj4 = new B(this, fileContent, "UInt8");
break;
case "UInt16":
B obj1 = new B(this, fileContent, "UInt16");
break;
case "UInt32":
B obj2 = new B(this, fileContent, "UInt32");
break;
case "UInt64":
B obj3 = new B(this, fileContent, "UInt64");
goto
default;
default:
MessageBox.Show("check");
break;
}
}
private void ButtonClick_EVENT(object sender, RoutedEventArgs e)
{
// I try to listen outside the class this way.
if (simpleEvent != null)
simpleEvent();
}
}
Class B
{
public B(MainPage Obj, byte[] fileContent, string type)
{
switch (type = Obj.comboBox1.SelectedItem as string)
{
case "UInt8":
{
//do something
break;
}
case "UInt16":
{
//do something
break;
}
case "UInt32":
{
//do something
break;
}
case "UInt64":
{
//do something
goto
default;
}
default:
{
break;
}
}
Obj.simpleEvent += () = > MyMethod(Obj);
}
public void MyMethod(MainPage Obj)
{
// This MessageBox repeats 2 times on second time button click
// and 3 times on 3rd button click .
// It should be called once even on second/third/fourth etc. button clicks.
MessageBox.Show("Repetition check");
}
}
}
The problem is my method is called repetitively. For example, when I click the button the first time it will be called only once (which is good). and if I click the button again the message box pop-up comes up 2 times and again pop-ups 3 times on 3rd attempt.
What I want is to pop-up this message box only once on the click (even if I keep on clicking on the button one after the other click).
EDIT: The new updated code is the actual situation i was trying to make it short so last time i didn't include to much code (because i was not suspecting that part).
What i am trying to do is :
I have to select 1 data type among 4 given data type at run time (uint64/32/16/8)(which will be data type for reading a file ("fileContent" in constructor call), but it's not related to question i asked, so leaving too much discussion on it).After selecting that data type i click the button to display something. (so each time i first i select "data type" from combo box and then i press button to display some data corresponding to that data type then i again select another data type from combo box and then again i press "button" but this time it pop-ups message 2 times, and when i repeat the same 3rd time it pop-ups messagebox 3times).
Suppose first i selected "uint64" in combo box at run time (in the first attempt) and then i click button to display messagebox it will pop-up the message box once.Now without closing the application my second selection to combo box is on uint32 (On second attempt) and again i click to "button" this time this message box is popped 2 times. I don't know why? and on third attempt it pop-ups 3 times.
(1) Why message box repeats ?
Thanks for the help in advance, I really wanna know the reason for it, not able to understand yet.
You're creating a new B object every time your combobox is changed. That adds a new handler every single time, without ever removing the previous handlers. You need to either unsubscribe the old handler when you go to add a new one, or only ever add one handler and simply modify the data that it relies on so that that handler acts appropriately when it fires.