UWP: Xamarin Forms Tabbed Page changing page doesn't call OnAppearing - tabs

In a Xamarin Forms project, I have created a TabbedPage inside which I have added 5 child navigation pages.
{
Children.Add(new NavigationPage(new A()));
Children.Add(new NavigationPage(new B()));
Children.Add(new NavigationPage(new C()));
Children.Add(new NavigationPage(new D()));
Children.Add(new NavigationPage(new E()));
}
When I click manually on a tab B from Tab A; B's OnAppearing method is called as expected. However when I programmatically change the tab using
tabbedPage.CurrentPage = tabbedPage.Children[index]
Then B's OnAppearing method is called never. This is happening on UWP.

As of Xamarin Forms 3.4.0.1008975 and UWP 6.1.5 this still appears to be an issue. I solved it like this:
Make an interface called IAppearable:
internal interface IAppearable
{
void HandleAppearing();
}
Have your content page implement this interface:
public partial class MyContentPage : ContentPage, IAppearable
In HandleAppearing do what you would have done in OnAppearing:
public void HandleAppearing()
{
// do appearing stuff here
}
After you programmatically set your tab page use this code:
CurrentPage = Children[pageIndex];
if (Device.RuntimePlatform == Device.UWP)
{
if (CurrentPage is IAppearable appearablePage)
{
appearablePage.HandleAppearing();
}
}

Related

Open an angular template reference in a new browser window

So here is the explanation of the problem I am facing. It might look very similar other already asked questions, but none of them answered my problem.
I want to open an angular template reference in a new browser window (with all the styles) and use that window to print the contents using system print dialog.
By template reference I mean a whole component or may be just a fraction of template of given component.
Please note that I do not want to do it by below methods:
Opening a new route in a new browser window. (Why? this will cause all other things like common toolbar or help open up with the component. Also a new route will be required which is undesired.)
Opening the content in a closable modal.
Ok, This is how I did it using ComponentFactoryResolver and Injector. Just inject these two dependencies in your component which wants to open other component (ReportComponent in this case) in new browser window.
The constructor looks something like this in snippet below.
constructor(
private resolver: ComponentFactoryResolver,
private injector: Injector
) {}
.
.
.
This method opens up the component in new browser window.
public openPrintableReport(): void {
// resolve and instantiate the component which you want to open in new window.
const componentFactory = this.resolver.resolveComponentFactory(ReportComponent);
let component = componentFactory.create(this.injector);
component.changeDetectorRef.detectChanges();
// define external window
this.externalWindow = window.open('', '', 'width=1000,height=1000,left=150,top=200');
// copy all the styles to external window.
document.querySelectorAll('style').forEach(htmlElement => {
this.externalWindow.document.head.appendChild(htmlElement.cloneNode(true));
});
this.externalWindow.document.title = 'Printer Friendly Report';
// attach the component to external window
this.externalWindow.document.body.appendChild(component.location.nativeElement);
}

From Polymer3 to lit-element and material components: replacement for paper-tabs and iron-pages

I am porting a Polymer 3 app to lit-element stepwise and also want to replace the paper and iron elements by material web components. I very often am using the combination of paper-tabs and iron-pages to show property pages/dialogs.
What would be the replacement for paper-tabs/iron-pages in the material web components world?
I have found mwc-tab-bar but there is no example for actually displaying contents according to the selected tab.
Has anyone an example for how to build what sometimes is called a page-control (tabs plus contents)?
There are several options: (I would prefer 1 & 3)
You could just create a condition to render and eventually lazy load a certain page.
Use something like lion-steps (they also provide tabs)
Use a router like simple-wc-router
class MyElement extends LitElement {
static get properties() {
return {
page: String,
}
}
get _oneTemplate() {
return html`Page one`;
}
get _twoTemplate() {
return html`Page two`;
}
constructor() {
super();
this.page = 'one';
setTimeout(() => (this.page = 'two'), 5000);
}
render() {
return this.page === 'one' ? this._oneTemplate : this._twoTemplate;
}
}

CDHtmlDialog crashes while navigating to pdf after navigating to google

Navigate from www.google.com page to pdf file causes exception in CDHtmlDialog.
This exception is not present while navigating from pages other than google (e.g. www.wikipedia.org).
Overridden "OnBeforeNavigate", "OnNavigateComplete" and "OnDocumentComplete" events. Then found that, in issue scenario, while loading pdf file "OnNavigateComplete" is called twice.
The calling sequence is as follows: OnBeforeNavigate=>OnNavigateComplete=>OnNavigateComplete
As "OnNavigateComplete" is called without calling "OnBeforeNavigate", "m_spHtmlDoc" in CDHtmlDialog does not become NULL and validation causes assertion in "CDHtmlDialog::OnNavigateComplete".
ASSERT(m_spHtmlDoc==NULL);
Header:
class CClientAppDlg : public CDHtmlDialog
cpp:
CClientAppDlg::CClientAppDlg(CWnd* pParent /*=nullptr*/)
: CDHtmlDialog(IDD_CLIENTAPP_DIALOG, 0, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CClientAppDlg::OnBnClickedNavigate()
{
UpdateData(TRUE);
Navigate(m_csNavURL); // Get URL from edit box and navigate
UpdateData (FALSE);
}
void CClientAppDlg::OnBeforeNavigate( LPDISPATCH pDisp, LPCTSTR szUrl)
{
CDHtmlDialog::OnBeforeNavigate(pDisp, szUrl);
}
void CClientAppDlg::OnNavigateComplete( LPDISPATCH pDisp, LPCTSTR szUrl)
{
CDHtmlDialog::OnNavigateComplete(pDisp, szUrl);
}
void CClientAppDlg::OnDocumentComplete(LPDISPATCH pDisp, LPCTSTR szUrl)
{
CDHtmlDialog::OnDocumentComplete(pDisp, szUrl);
}
Why "OnNavigateComplete" is called twice and causing exception?
Why does it happen only while navigating from google page?

Angular2 e2e not accessing Boostrap modal element

I'm running some e2e tests on an Angular2 app. One test involves clicking a button to open a Bootstrap modal. Even though I simulate the click of the button in my e2e test, it seems I cannot access the modal.
I'm currently just trying to run a simple test to click the button, open the modal, and check the text in an h4 element within the modal.
app.po.ts:
import { browser, element, by } from 'protractor';
export class SolarUi4Page {
navigateTo() {
return browser.get('http://localhost:4200/');
}
getAddButton() {
return element(by.css('.icon-plus'));
}
//2nd and 3rd lines attempt to do the same thing. Neither work
getH4() {
//return element(by.css('main-page')).element(by.id('data')).getText();
//return element(by.css('add-validation')).element(by.tagName('h4')).getText();
return element(by.css('h4')).getText();
}
}
app.e2e-spec.ts:
import { SolarUi4Page } from './app.po';
describe('solar-ui4 main page', function() {
let page: SolarUi4Page;
beforeEach(() => {
page = new SolarUi4Page();
});
it('should add new value to array/table and display it', () => {
page.navigateTo();
let addButton = page.getAddButton();
addButton.click();
expect(page.getH4()).toEqual('Add Data Point');
});
});
app.component.html (contains three custom components):
<main-page></main-page>
<add-validation></add-validation>
<delete-validation></delete-validation>
I am able to access any element inside the main-page component via syntax like the first commented out line in getH4() method. It seems I cannot access anything from the add-validation element, which is my Bootstrap modal. I'm assuming it is because that HTML is not present on the page on load, but shouldn't addButton.click(); trigger the modal to open so it IS present?
You might need to wait for the popup to be visible via browser.wait():
var EC = protractor.ExpectedConditions;
var elm = element(by.css('h4'));
browser.wait(EC.visibilityOf(elm), 5000);
expect(elm.getText()).toEqual('Add Data Point');

Put wizard navbar on top position

I'm working with a wizard component. The navbar is in the botton but my boss wants me to put it in the top of the wizard,I thought that it was an attribute or tag to do it straight forward but I have been reviewing the documentation and I should be wrong (I only found the showNavBar tag).
Is there a way to do it without css or jquery? (we have some problems in the application setting css when working with some components so I would like to avoid it).
Thank you very much
You can achieve this in either of the two ways:
1 - Extending the WizardRenderer
By extending the WizradRenderer you can change the order of the encoding.
In the original Renderer the encodeContent(facesContext, wizard); is called before encodeNavigators(facesContext, wizard); so it's pretty much simple, extend you custom renderer, change the order of the calls.
public class ExNavWizardRenderer extends org.primefaces.component.wizard.WizardRenderer{
#Override
protected void encodeMarkup(FacesContext facesContext, Wizard wizard) throws IOException {
ResponseWriter writer = facesContext.getResponseWriter();
String clientId = wizard.getClientId(facesContext);
String styleClass = wizard.getStyleClass() == null ? "ui-wizard ui-widget" : "ui-wizard ui-widget " + wizard.getStyleClass();
writer.startElement("div", wizard);
writer.writeAttribute("id", clientId, "id");
writer.writeAttribute("class", styleClass, "styleClass");
if(wizard.getStyle() != null) {
writer.writeAttribute("style", wizard.getStyle(), "style");
}
if(wizard.isShowStepStatus()) {
encodeStepStatus(facesContext, wizard);
}
// encode the navigators before the content
if(wizard.isShowNavBar()) {
encodeNavigators(facesContext, wizard);
}
encodeContent(facesContext, wizard);
writer.endElement("div");
}
}
Update your faces-config.xml
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.WizardRenderer</renderer-type>
<renderer-class>com.projectPackage.ExNavWizardRenderer</renderer-class>
</renderer>
</render-kit>
2 - jQuery
In your document.ready you can change the DOM, for example this would do the same as the Renderer:
$('.ui-wizard-step-titles').after($('.ui-wizard-navbar'))