Always Check if there is Internet Connection Xamarin forms - c#

I am doing a xamarin forms app, i want to check every second if there is a internet connection, if the connection is lost, the program should go to diferent page.
I am using the plugin "Xam.Plugin.Connectivity" , but doesnt do what i want.
Is possible to do what i want?

Edit: this can be easily done with the new Xamarin Essentials Connectivity plugin, just follow the instructions there :D
Create a method in your App.cs (or App.xaml.cs) like this:
private async void CheckConnection()
{
if(!CrossConnectivity.Current.IsConnected)
await Navigation.PushAsync(new YourPageWhenThereIsNoConnection());
else
return;
}
And use it on your main app method like this:
public App()
{
InitializeComponent();
var seconds = TimeSpan.FromSeconds(1);
Xamarin.Forms.Device.StartTimer(seconds,
() =>
{
CheckConnection();
});
}

Never used, but this is a documentation about the plugin you are using
Detecting Connectivity Changes
Often you may need to notify your user or respond based on network changes. You can do this by subscribing several different events.
Changes in Connectivity
When any network connectivity is gained, changed, or loss you can register for an event to fire:
/// <summary>
/// Event handler when connection changes
/// </summary>
event ConnectivityChangedEventHandler ConnectivityChanged;
You will get a ConnectivityChangeEventArgs with the status if you are connected or not:
public class ConnectivityChangedEventArgs : EventArgs
{
public bool IsConnected { get; set; }
}
public delegate void ConnectivityChangedEventHandler(object sender, ConnectivityChangedEventArgs e);
CrossConnectivity.Current.ConnectivityChanged += async (sender, args) =>
{
Debug.WriteLine($"Connectivity changed to {args.IsConnected}");
};
Changes in Connectivity Type
When any network connectivity type is changed this event is triggered. Often it also is accompanied by a ConnectivityChanged event.
/// <summary>
/// Event handler when connection type changes
/// </summary>
event ConnectivityTypeChangedEventHandler ConnectivityTypeChanged;
When this occurs an event will be triggered with EventArgs that have the most recent information:
public class ConnectivityTypeChangedEventArgs : EventArgs
{
public bool IsConnected { get; set; }
public IEnumerable<ConnectionType> ConnectionTypes { get; set; }
}
public delegate void ConnectivityTypeChangedEventHandler(object sender, ConnectivityTypeChangedEventArgs e);
Example:
CrossConnectivity.Current.ConnectivityTypeChanged += async (sender, args) =>
{
Debug.WriteLine($"Connectivity changed to {args.IsConnected}");
foreach(var t in args.ConnectionTypes)
Debug.WriteLine($"Connection Type {t}");
};

Related

Xamarin IOS: BLE

I am trying to connect to my Bluetooth Low Energy Device. After finding the device and getting the peripheral object. I cannot connect to the Bluetooth Device from my iPhone and it does not call central.ConnectedPeripheral method.
Another issue is that i cannot register the event central.ConnectedPeripheral += ConnectedPeripheral in the method.
Error: System.InvalidOperationException: Event registration is overwriting existing delegate. Either just use events or your own delegate:
class IOSBluetooth : IBluetooth
{
private readonly CBCentralManager central;
private CBPeripheral activePeripheral;
SimpleCBCentralManagerDelegate myCentralDelegate;
public bool IsScanning { get; private set; }
List<CBPeripheral> connectedDevices = new List<CBPeripheral>();
//List<CBPeripheral> discoveredDevices = new List<CBPeripheral>();
/// <summary>
/// Gets the current Bluetooth instance
/// </summary>
/// <value>The Bluetooth Adapter instance</value>
public IOSBluetooth(SimpleCBCentralManagerDelegate myCenDel)
{
myCentralDelegate = myCenDel;
central = new CBCentralManager(myCentralDelegate, DispatchQueue.CurrentQueue);
InitializeEvents();
// central.DiscoveredPeripheral += DiscoveredPeripheral; // Called when peripheral is discovered (Working)
// central.UpdatedState += UpdatedState; // Method Implemented - Tells us about the bluetooth powered state (On or Off). (Working)
// central.ConnectedPeripheral += ConnectedPeripheral; // Devices that are connected to Iphone -> Services and Characteristics discovery start from here
// central.DisconnectedPeripheral += DisconnectedPeripheral; // Disconnect the device from the iphone
// central.FailedToConnectPeripheral += FailedToConnectPeripheral; // Failed to connect to Bluetooth Device
}
void InitializeEvents()
{
try
{
// central.ConnectedPeripheral += ConnectedPeripheral;
central.FailedToConnectPeripheral += FailedToConnectPeripheral;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message, "Intialization Failes");
Console.WriteLine("Bluetooth.Connect " + ex.Message);
}
}
public void FailedToConnectPeripheral(object sender, CBPeripheralErrorEventArgs e)
{
Console.WriteLine("Failed to Connect to Peripheral");
}
private void DisconnectedPeripheral(object sender, CBPeripheralErrorEventArgs e)
{
// when a peripheral disconnects, remove it from our running list.
if (connectedDevices.Contains(e.Peripheral))
{
connectedDevices.Remove(e.Peripheral);
}
}
public void ConnectToPeripheral(CBPeripheral peripheral)
{
central.ConnectPeripheral(peripheral, new PeripheralConnectionOptions { NotifyOnConnection = true, NotifyOnDisconnection = true, NotifyOnNotification = true });
}
private void UpdatedState(object sender, EventArgs e)
{
throw new NotImplementedException();
}
//public override void DiscoveredPeripheral(object sender, CBDiscoveredPeripheralEventArgs e)
//{
// Console.WriteLine("DiscoveredPeripheral: {0}", e.Peripheral.Name);
// discoveredDevices.Add(e.Peripheral);
//}
public void ConnectedPeripheral(object sender, CBPeripheralEventArgs e)
{
if (!connectedDevices.Contains(e.Peripheral))
{
connectedDevices.Add(e.Peripheral);
}
activePeripheral = e.Peripheral;
Console.WriteLine("Connected to " + activePeripheral.Name);
if (activePeripheral.Delegate == null)
{
activePeripheral.Delegate = new SimplePeripheralDelegate();
//Begins asynchronous discovery of services
activePeripheral.DiscoverServices();
}
}
public async void BeginScanningForDevices()
{
Console.WriteLine("BluetoothLEManager: Starting a scan for devices.");
// start scanning
IsScanning = true;
central.ScanForPeripherals((CBUUID[])null); // Discover all the devices and Initiates async calls of DiscoveredPeripheral
// in 10 seconds, stop the scan
await Task.Delay(10000);
// if we're still scanning
if (IsScanning)
{
Console.WriteLine("BluetoothLEManager: Scan timeout has elapsed.");
StopScanningForDevices();
}
}
/// <summary>
/// Stops the Central Bluetooth Manager from scanning for more devices. Automatically
/// called after 10 seconds to prevent battery drain.
/// </summary>
public void StopScanningForDevices()
{
Console.WriteLine("BluetoothLEManager: Stopping the scan for devices.");
IsScanning = false;
central.StopScan();
}
public IEnumerable<string> ListDevices()
{
return myCentralDelegate.DiscoveredDevices.Keys;
}
public bool Connect(string DeviceName)
{
StopScanningForDevices();
if (!myCentralDelegate.DiscoveredDevices.ContainsKey(DeviceName))
return false;
var device = myCentralDelegate.DiscoveredDevices[DeviceName];
// central.ConnectPeripheral(device, new PeripheralConnectionOptions { NotifyOnConnection = true, NotifyOnDisconnection = true, NotifyOnNotification = true });
central.ConnectPeripheral(device);
return true;
}
public void StartScanning()
{
if(central.State == (CBCentralManagerState.PoweredOn))
BeginScanningForDevices();
}
public void StopScanning()
{
StopScanningForDevices();
}
}
To get rid of the "Error: System.InvalidOperationException: Event registration is overwriting existing delegate. Either just use events or your own delegate" error, implement the ConnectedPeripheral method in the SimpleCBCentralManagerDelegate class. That class is being used as the iOS delegate (not to be confused with a C# delegate) so all of the events from CBCentralManager central are being handled in the relevant methods in the SimpleCBCentralManagerDelegate class.
The idea here is that you can either use the iOS style delegate/protocol pattern, where a delegate class that implements an Obj-C/iOS protocol is assigned as the iOS/Obj-C delegate for the class that will call those protocol methods, or you can use C# style event subscriptions, but you can't use both on the same object.
More info on this is discussed on this document: https://learn.microsoft.com/en-us/xamarin/ios/app-fundamentals/delegates-protocols-and-events
It's a long read but well worth it if you are developing using Xamarin.iOS.

Why connectivity plugin network handler not working when navigation happens

In case the network connectivity isn’t on to check if it is off, so, that I’m using to connectivity plug in.
I'm calling this code in ViewModelLocator class
Private static async void NetworkConnectivityChanged(object sender,Plugin.Connectivity.Abstractions.ConnectivityChangedEventArgs e){}
CrossConnectivity.Current.ConnectivityChanged = NetworkConnectivityChanged;
In my windows app after navigating if network connectivity status changed … Here this event is not fire but if not using navigation, we change the network status and it happens it's working.
The workaround is to implement the native network change handler on Winphone or UWP side and stop handling of network change on PCL side for just Winphone and UWP. You can do this by checking the platform before handling.
Create a new Network.cs class with the following code(This detects if there is any change in network connection)
public class InternetConnectionChangedEventArgs : EventArgs
{
public InternetConnectionChangedEventArgs(bool isConnected)
{
this.isConnected = isConnected;
}
public bool IsConnected
{
get { return this.isConnected; }
}
private bool isConnected;
}
public static class Network
{
public static event EventHandler<InternetConnectionChangedEventArgs>
InternetConnectionChanged;
static Network()
{
NetworkInformation.NetworkStatusChanged += (s) =>
{
if (InternetConnectionChanged != null)
{
var arg = new InternetConnectionChangedEventArgs(IsConnected);
InternetConnectionChanged(null, arg);
}
};
}
public static bool IsConnected
{
get
{
var profile = NetworkInformation.GetInternetConnectionProfile();
var isConnected = (profile != null
&& profile.GetNetworkConnectivityLevel() ==
NetworkConnectivityLevel.InternetAccess);
return isConnected;
}
}
}
Then in the app.xaml.cs in UWP or WinPhone register the network change handler in OnLaunched event like below
Network.InternetConnectionChanged += this.Network_InternetConnectionChanged;
and here is the event handler
private void Network_InternetConnectionChanged(object sender,InternetConnectionChangedEventArgs e)
{
if(e.IsConnected){
///code to handle when the internet connectivity is there
}
else{
//code to handle when the internet connectivity is lost
}
}

Keep MiDi output playing when UWP goes into background

I'm trying to build a metronome application that has the capability to run in the background. As a starting point I decided to create something simple, a class that has a timer (the metronome itself), a class responsible for obtaining the MIDI output device and a class to play the sound. I'm having difficulty with how to make this run in the background. Additionally, another problem is the fact that the metronome needs to be executed when clicking an application button (in the main process).
Metronome Class:
public class Metronome
{
private DispatcherTimer timer = new DispatcherTimer();
private MidiDeviceSelector deviceSelector = new MidiDeviceSelector();
private void TimerStart()
{
timer.Start();
timer.Tick += timer_Tick;
}
private void timer_Tick(object sender, object e)
{
AudioPlayback.Beep1();
}
public void Start(int bpm)
{
double interval = (double)60.000f / (bpm);
timer.Interval = TimeSpan.FromSeconds(interval);
TimerStart();
}
public void Stop()
{
timer.Stop();
}
}
MidiDeviceSelector:
class MidiDeviceSelector
{
public MidiDeviceSelector()
{
GetOutputMidiDevice();
}
public async void GetOutputMidiDevice()
{
IMidiOutPort currentMidiOutputDevice;
DeviceInformation devInfo;
DeviceInformationCollection devInfoCollection;
string devInfoId;
devInfoCollection = await DeviceInformation.FindAllAsync(MidiOutPort.GetDeviceSelector());
if (devInfoCollection == null)
{
//notify the user that any device was found.
System.Diagnostics.Debug.WriteLine("Any device was found.");
}
devInfo = devInfoCollection[0];
if (devInfo == null)
{
//Notify the User that the device not found
System.Diagnostics.Debug.WriteLine("Device not found.");
}
devInfoId = devInfo.Id.ToString();
currentMidiOutputDevice = await MidiOutPort.FromIdAsync(devInfoId);
if (currentMidiOutputDevice == null)
{
//Notify the User that wasn't possible to create MidiOutputPort for the device.
System.Diagnostics.Debug.WriteLine("It was not possible to create the OutPort for the device.");
}
MidiDevice.midiDevice = currentMidiOutputDevice;
}
Class to Holds the MidiDevice:
class MidiDevice
{
public static IMidiOutPort midiDevice; //Bad practice i know.
}
Class to play the "toc" sound:
class AudioPlayback
{
static IMidiMessage beep1 = new MidiNoteOnMessage(9, 76, 90);
//static IMidiOutPort midiOutputDevice = (IMidiOutPort)MidiDeviceSelector.GetOutputMidiDevice();
public static void Beep1()
{
try
{
MidiDevice.midiDevice.SendMessage(beep1);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
}
}
Each class is contained in a different file. As you can see, it is a very simple code, if you see any bad programming practice, I apologise, I do not have much experience.
I was looking at the documentation, however, I did not succeed. How do I register an activity in the background and that there is interaction with the application's user interface (a button to stop and start the metronome).
My apologies for bad English, not my native language.
Thank you.
Two things you need to add to make this scenario work:
add the "backgroundMediaPlayback" capability as documented here: https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/background-audio
since you are using the MiDI APIs, you need to explicitly integrate with the SystemMediaTransportControls to prevent getting muted on minimize
I have update your repro sample and verified that it works correctly after adding those two things.
Sharing it here for your reference: https://1drv.ms/u/s!AovTwKUMywTNl9QJTeecnDzCf0WWyQ

Subscribe to category stream, event never appears in subscription client

Being a first time user of GetEventStore and having read the docs, I have an issue where events never appears on my subscription client.
This is possible due to a configuration step I've missed.
Having this console application client:
public class EventStoreSubscriptionClient : ISubscriptionClient
{
private const string GroupName = "liner";
private const string StreamName = "$ce-happening";
private readonly IProvideEventStoreConnection _eventStoreConnection;
private readonly UserCredentials _userCredentials;
private EventStorePersistentSubscriptionBase EventStorePersistentSubscriptionBase { get; set; }
public EventStoreSubscriptionClient(IProvideEventStoreConnection eventStoreConnection, UserCredentials userCredentials)
{
_eventStoreConnection = eventStoreConnection;
_userCredentials = userCredentials;
}
public void Connect()
{
var connection = _eventStoreConnection.ConnectAsync().Result;
EventStorePersistentSubscriptionBase = connection.ConnectToPersistentSubscription(
StreamName,
GroupName,
EventAppeared,
SubscriptionDropped,
_userCredentials,
10,
false
);
}
private void SubscriptionDropped(EventStorePersistentSubscriptionBase subscription, SubscriptionDropReason reason, Exception ex)
{
Connect();
}
private async void EventAppeared(EventStorePersistentSubscriptionBase subscription, ResolvedEvent resolvedEvent)
{
Console.WriteLine("Event appeared: " + resolvedEvent.Event.EventId);
}
public void Dispose()
{
EventStorePersistentSubscriptionBase.Stop(TimeSpan.FromSeconds(15));
}
}
Upon starting this console application, the connection goes fine to http://myserver:1113. In the administration panel of my event store I can see there is a connection to this stream/group on the competing consumers tab:
But if I send a event like to happening-<guid> it shows up on the stream browser, but my subscription client never gets an event appeared event:
Have I misunderstood on how subscriptions, streams and groups works? Please enlighten me.
The answer here is that projections for the Event Store was disabled.
Start the store with --run-projections=all

Addressed event subscription

In several of my projects, it is becoming apparent that I need something slightly more powerful than the standard .NET events.
Basically, I want the option of within a message pump, having callbacks (events) raised to specific subscribers when the component they're interested changes.
This could be a specific I/O changing state (e.g. button closing contact) for one project, or a message received from a wireless ethernet for a specific MAC address in another.
My current line of thinking is to use a dictionary, and list of delegates against each address (for this example).
I haven't debugged this yet but is the following along the right lines?
class CustomSubscription
{
public delegate void DataReceivedHandler(object sender, DataReceivedEventArgs args);
public class DataReceivedEventArgs : EventArgs
{
public byte[] data;
}
private readonly Dictionary<int, List<DataReceivedHandler>> _subscribers;
public CustomSubscription()
{
_subscribers = new Dictionary<int, List<DataReceivedHandler>>();
}
public void AddSubscriber(int address, DataReceivedHandler callback)
{
if (false == _subscribers.ContainsKey(address))
{
_subscribers.Add(address, new List<DataReceivedHandler>());
}
_subscribers[address].Add(callback);
}
public void RemoveSubscriber(int address, DataReceivedHandler callback)
{
if (false == _subscribers.ContainsKey(address))
{
return;
}
if (_subscribers[address].Contains(callback))
{
_subscribers[address].Remove(callback);
}
}
public void HandleIncommingData(int address, object sender, byte[] payload)
{
if (false == _subscribers.ContainsKey(address))
{
// Nothing subscribed - take no action
return;
}
// Raise callbacks with all subscribers
foreach (DataReceivedHandler callback in _subscribers[address])
{
callback(sender, new DataReceivedEventArgs
{
data = payload
});
}
}
}
Looks like you are trying to implement an event aggregator pattern. There are plenty implementations already on the web. You can start from here, for example:
https://stackoverflow.com/questions/2343980/event-aggregator-implementation-sample-best-practices

Categories