How to edit the function of the close button on MAUI Blazor Hybrid - button

I am working on an application written in MAUI Blazor.
I would like that after click on the red button "Close", to bring up the message "Are you sure you want to close the application?".
How to modify the function of the close system button on Windows?
I tried used OnClosed event but I don't know how to use it correctly.
#if WINDOWS
events.AddWindows(wndLifeCycleBuilder =>
{
wndLifeCycleBuilder.OnClosed((window, args) => LogEvent("OnClosed"));
wndLifeCycleBuilder.OnWindowCreated(window =>
{
//Set size and center on screen using WinUIEx extension method
window.CenterOnScreen(400, 750);
window.ExtendsContentIntoTitleBar = true;
});
});
#endif
I mean this button.

Related

DispatchKeyEvent stops firing after Xamarin Forms Entry control IsFocused

I am building a Xamarin Forms mobile app that runs in Android on a Zebra scanner. I flip 2 different StackLayouts to IsVisble true/false to display different stuff in the UI. (StackLayout1 and StackLayout2)
The customer wants the user to be able to use the app entirely from the hardware keyboard on the scanner. So I have used the device Settings so that it never displays the virtual keyboard (I don’t think that matters for the issue I am having.)
I am overriding DispatchKeyEvent in a PageRenderer in the Android project and everything is working great … except.
The problem case:
StackLayout1 is displayed
the user taps an Entry control, putting the focus there
the user taps a button in the UI
the app displays StackLayout2
at this point the DispatchKeyEvent never fires no matter what key I press on the device keyboard
If an Entry box does NOT get the focus (step #2 above) the DispatchKeyEvent always fires in StackLayout2 and the StackLayouts display as expected.
If I programatically put the focus in an Entry box in StackLayout2 at step #3 above the DispatchKeyEvent fires fine.
That is not an OK solution. I have tried to progamatically put the focus on StackLayout2, and that code seems to do what is expected but DispatchKeyEvent does not fire.
Maybe I need to do something in the Android-project PageRenderer so that it is aware of StackLayout2 when it is made IsVisible = true.
Update 2: I found that I did NOT need custom StackLayouts. The solution which I posted below does not include any of this stuff I am describing in Update 1 (sorry, if that's confusing).
Update 1:
I added a ViewRenderer for both StackLayouts, and the code is hitting the OnElementChanged event when StackLayout2's IsVisible property flips to true, just great. Although the problem case is the same: DispatchKeyEvent does not fire once StackLayout2 is displayed, if an EntryBox had the focus in StackLayout1
Here is the OnElementChanged part of the new StackLayout ViewRenders
async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "IsVisible":
if (Element.IsVisible)
{
if (sender is StackLayout)
{
this.FocusableViewAvailable(this); // if I comment these 2 lines out I get the same bad result
this.Focusable = true; // if I comment these 2 lines out I get the same bad result
this.FocusableInTouchMode = true;
var dd = this.RequestFocus(); // this is always false
var ee = this.IsFocused; // this is always false
}
}
break;
}
}
Also, as I am pointing out in the comments ^ there, IsFocused is always false.
Ideas?
My hunch, "Maybe I need to do something in the Android project PageRenderer" was correct. In the DispatchKeyEvent I had to make the MainPage have the focus when the keypress was handled.
Here is what the DispatchKeyEvent looks like now (notice the comments):
public override bool DispatchKeyEvent(KeyEvent ke)
{
// MainPage.ReceiveKeyPress(e); is the method that this method returns to
bool KeyPressWasHandled = false;
KeyPressWasHandled = (Element as MainPage).ReceiveKeyPress(ke);
if (KeyPressWasHandled)
{
// this next block seems to be needed so that this class
// continues to receive the keypress event after an Entry box has had the focus
this.Focusable = true;
this.FocusableInTouchMode = true;
this.RequestFocus();
return true; // returning true tells the parent class that the keypress has been handled
} else
{
try
{
return base.DispatchKeyEvent(ke);
}
Now the "problem case" in my initial post is no longer a problem.
NOTE: I found that I did NOT need the custom ViewRenderers that I had made for the StackLayouts.

How to close multiple dialog box using Angular

I have a running Angular 9 application and I have created custom dialog box. I have also used ComponentFactoryResolver to dynamically load the component.
My custom dialog box looks like:
So, when I click on close button, the dialog box closes.
As per the current implementation, if I open multiple dialog box on the screen, then I am able to close only last opened dialog box by clicking on close button.
My expected behavior is to close all the dialog box. Please help me on this
Stackblitz demo: https://stackblitz.com/edit/dialog-box-overlay
Note: In this stackblitz demo, one modal opens on the top of another modal as I have not modified the css. So, please focus on Modal name to get to know which modal is opened
Instead of assigning the created modal component to the services dcRef property you need to manage all of your modal components, i.e. in a list. Your service's open() method
open(component: Type<any>, modalName: string) {
const factory = this.componentFactoryResolver.resolveComponentFactory(DialogComponent);
this.dcRef = factory.create(this.injector);
...
return this.dcRef;
}
returns the component reference. You could manage this reference from the caller and pass it as an argument to your close() method. When all of the component refs are managed by the service you can also "batch close" all modals (see closeAll()):
#Injectable()
export class DialogService {
refs: ComponentRef<DialogComponent>[] = [];
constructor(private componentFactoryResolver: ComponentFactoryResolver,
private applicationRef: ApplicationRef,
private injector: Injector
) { }
open(component: Type<any>, modalName: string) {
const factory = this.componentFactoryResolver.resolveComponentFactory(DialogComponent);
var ref = factory.create(this.injector);
this.applicationRef.attachView(ref.hostView);
const domElement = (ref.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
document.body.appendChild(domElement);
ref.changeDetectorRef.detectChanges();
ref.instance.open(component, modalName);
this.refs.push(ref);
return ref;
}
close(ref) {
this.applicationRef.detachView(ref.hostView);
ref.instance.close();
ref.destroy();
// Remove ref from a list managed by the service
var i = this.refs.indexOf(ref);
this.refs.splice(i, 1);
}
closeAll()
{
this.refs.forEach(r => this.close(r));
}
}
This is not tested and might need to be tuned, but you should get the idea. Instead of using the ComponentRef as a handle you can also create some custom object to prevent the caller of the modal to interact with the component directly.

Xamarin Forms - Duplicate Screens

I'm writing an app using Xamarin Forms and I have an issue I was hoping someone can help with.
My app contains a screen which has multiple icons that can be pressed which would then open a new screen.
My issue is that if you press the icon twice really fast, the app opens up 2 instances of the same screen (it's not just related to a double press, if you press the icon 6 times very fast it will open up 6 duplicate screens). Pressing the Back button, closes the top screen to reveal the duplicate screen underneath. Pressing the Back button again navigates you back to the original screen.
This issue seems to occur on any screen within my app so I'm hoping other people will have experienced it and know of a solution to prevent duplicate screens being displayed.
This is a known issue in TapEvents.
My hack is, in the code-behind, have a bool variable _canTap.
Inside the method you are calling to push new page, first you check if canTap, then set to false, and only set to true after navigating to another page. This way all taps will be disregarded.
Example:
private bool _canTap = true;
public void YourMethod()
{
if(_canTap)
{
_canTap = false;
YourMethodToNavigate();
_canTap = true;
}
}
In the Icon_Pressed method add this,
this.IsEnabled = false;
await Navigation.PushAsync(new MyPage());
this.IsEnabled = true;
It disables the page until the current Icon pressed event is finished
This is known problem with Xamarin apps. I've used a private variable combined with a try-finally pattern to solve this. Ex:
bool allowTap = true;
public void ButtonTapped()
{
try
{
if(allowTap)
{
allowTap = false;
// Do whatever...
}
}
finally
{
allowTap = true;
}
}
The finally makes sure allowTap gets set back to true no matter what happens, short of a complete crash. Note that you can also use a catch block between the try and finally blocks to grab any errors if needed.

React-VR iFrame Fullscreen

Creating a React-VR app that I need to iFrame into an existing app. My question is regarding the fullscreen button. How can i either hide this button and manage within my other app or send a message to the parent that the button was clicked?
Couldn't find any official documentation for this but if you look at the implementation of VRInstance you'll notice a hideFullscreen option that hides that button.
// vr/client.js
const vr = new VRInstance(bundle, 'VRTEST', parent, {
hideFullscreen: true,
...options,
});
To toggle fullscreen mode for an iframe you can use a library like screenfull.js so you don't have to worry about the various cross-browser implementation details of the Fullscreen API.
Just render a button in your page and make it toggle fullscreen mode for a DOM element on click.
const vrIframe = document.getElementById('vrIframe');
document.getElementById('vrFullscreenButton').addEventListener('click', () => {
if (screenfull.enabled) {
screenfull.request(vrIframe);
}
});

Enable button function inside backgroundWorker

I am using windows form application to create gui. I have create a form with several button. The functionality of the first button called button1 is to read a video from hard disk and display it to a picturebox. The last line of button1 code is to enable another button:
button2->Enabled = true;
Button1 code is inside a backgroundworker. The result of this, it works fine, however it doesnt enable the button2. Is there issue using button properties inside backgroundworker?
You have to use BeginInvoke method and use Action delegate because backgroundworker DoWork doesn't modify UI.
private:
void DoWork(Object^ /*sender*/, EventArgs^ /*e*/ )
{
// some code
button2->BeginInvoke(gcnew Action(this, &MyForm::ModifyButton) );
}
void ModifyButton()
{
button2->Enabled = true;
}

Resources