Blazor Hybrid access Parent XAML Window - wpf

I assume the answer will be the same for MAUI and WinForms.
I have a WPF-BlazorHybrid application.
What is the best way to access the parent XAML window and it's ViewModel from Blazor code?
Xaml page:
<blazor:BlazorWebView HostPage="wwwroot\index.html" Services="{DynamicResource services}">
<blazor:BlazorWebView.RootComponents >
<blazor:RootComponent Selector="#app" ComponentType="{x:Type local:MainRouter}"/>
</blazor:BlazorWebView.RootComponents>
</blazor:BlazorWebView>
MainRouter:
#using BlazorHybrid.WPF.Views.BlazorComponents.Shared
#using Microsoft.AspNetCore.Components.Routing
<Router AppAssembly="#typeof(MainRouter).Assembly">
<Found Context="routeData">
<RouteView RouteData="#routeData" DefaultLayout="#typeof(MainBlazor)" />
<FocusOnNavigate RouteData="#routeData" Selector="h1" />
</Found>
<NotFound>
<LayoutView Layout="#typeof(MainBlazor)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
My first actual functional Blazor page is "MainBlazor".
I want to access my xaml window and viewmodel from here.

You can check Binding with component parameters, and component parameters permit binding properties of a parent component.

Related

ReactJS router + component hierarchy when swapping out components with route changes

TLDR: I'm trying to figure out how to arrange nested routes and my components so that a component can be swapped out based on route.
In SUPER simple terms, I'm trying to build an application where teachers can see the classes they teach at colleges.
The routes of the application are:
/dashboard: call backend to check if the teacher has a default college set on their account, if not then present a college picker dialog where the teacher can select a default college. Once there's a default college (say COLLEGE1), re-route to next route (next bullet point)
/dashboard/college/COLLEGE1: fetch metadata of classes taught in college.
/dashboard/college/COLLEGE1/class/CLASS1: show metadata of a single class within COLLEGE1. This route is accessed by clicking a class in bullet 2.
Here are rough mocks of what this interaction would look like when static (I've colored each component so it's easier for you to refer to them when responding):
However, I am just not able to figure out the nested routes + component hierarchy structure that would get me this.
The hierarchy I have so far is:
<Home>
<Header/>
<!-- content in header -->
</Header>
<MainContent>
<!-- Either loading, for e.g. to fetch permissions -->
<Loading />
<!-- OR display navigation + content -->
<MainContentPage>
<!-- show navigation pane on left, and then choose from report / T and Cs / Contact -->
<Navigation>
<CurrentCollegeInfo />
<DashboardLink />
<TermsAndConditionsLink />
<ContactUsLink />
</Navigation>
<ReportPage>
<!-- Either Loading -->
<Loading />
<!-- OR have user select default college -->
<DefaultCollegePickerPopup />
<!-- OR show college report or class details -->
<CollegeReportPage />
<ClassDetailsPage />
<!-- OR error pages: Not Found, 500, etc. -->
<ErrorPage />
</ReportPage>
<TermsAndConditionsPage />
<ContactUsPage />
</MainContentPage>
</MainContent>
</Home>
How do I insert route management here (I'm using react-router library at the moment btw) so that in the ReportPage component:
either the route is /dashboard (when loading default college from backend or asking user to pick one)
or it is /dashboard/college/COLLEGE1 and fetch college report
or it is /dashboard/college/COLLEGE1/class/CLASS1 and fetch class details?
Or is this not possible and I should rather figure out another flow?
So if I understand correctly, you want to use the react-router to load different components based on which endpoint the user is on? This is 100% possible. You just pass the component you want to show for a specific route as a component property.
You can also use parameters in the paths, so in your example, you have /dashboard/COLLEGE1... I'm assuming you need that to be dynamic to allow for any college. This is done with placing parameters into the path like so... /dashboard/:somevariablename.
<Route
// exact
path={"/dashboard"}
// path={"/dashboard/:collegeId"}
// path={"/dashboard/:collegeId/classes/:classId"}
component={ComponentToPass}
/>
If you make a Route for every possible component/page that the user can visit, and wrap it in a <Switch> component, it will show only one component. You can however skip the <Switch> and add multiple routes to an endpoint as well.
I'm assuming you'll need to use the collegeId and classId in the corresponding components. If you are using functional react, use const { VARNAME } = useParams() to retrieve the parameters you are using. If you are using class-based react, all you need to do is call this.props.match.VARNAME. -- Both are obviously used inside the component that you want to show/use.
So to change your code up a little bit (could be done in a dedicated routes component), heres a light example..
import {HashRouter, Switch, Route} from "react-router-dom"
import DefaultCollegePickerPopup from './wherever'
import CollegeReportPage from './wherever'
import ClassDetailsPage from './wherever'
function RouterComponent(props) {
return (
<HashRouter>
<Switch>
<Route
exact
path={"/dashboard"}
component={DefaultCollegePickerPopup}
/>
<Route
exact
path={"/dashboard/:collegeId"}
component={CollegeReportPage}
/>
<Route
exact
path={"/dashboard/:collegeId/class/:classId"}
component={ClassDetailsPage}
/>
</Switch>
</HashRouter>
)
}
function CollegeReportPage(props) {
const { collegeId } = useParams();
return (
<div>College report for {collegeId}</div>
)
}
class CollegeReportPage extends React.Component {
render() {
const { collegeId } = this.props.match
return (
<div>College report for {collegeId}</div>
)
}
}
If you haven't already looked at this, I would. It gives a LOT of useful information.
https://reactrouter.com/web/guides/quick-start

Unexpected rendering of nested div tags with same css class in react-admin show view - why and how to fix?

I made a custom ShowView in react-admin 3.2.4 view to show a large form for print.
While fine-tuning the css classes I noticed that there are two nested divs rendered with my custom css class arbeitserlaubnis_frame. Since the code is like below, I expected only one div with that particular class name.
<ShowController {...props} >
{controllerProps =>
<ShowView {...props} {...controllerProps} actions={<PostShowActions />}>
<SimpleShowLayout >
<div className="arbeitserlaubnis_frame" id="print_content1">
[...]
</div>
</SimpleShowLayout>
</ShowView>
}
</ShowController>
This is the result in the DOM:
Questions:
Why is it so?
How can I fix it that only one div with class arbeitserlaubnis_frame is rendered?

ReactJS: Dynamic Navbar Component determined by component prop

In my app, in the navbar, the menu hamburger and the back button are sharing the same space, and one or the other is shown based on page.
I would like to implement something like :
<Nav/>
<Page nav={backButton}/>
or
<Page nav={Menu}/>
Any ideas or links to docs would be greatly appreciated
Thanks!
Normally I'd try to make this prop driven. Your parent component can pass down a showBackButton prop that acts as a switch.
{ showBackButton ? <BackButton /> : <HamburgerMenu /> }

Admin-on-rest- How to Mix components in Resource and Show/Edit modes?

Now I am purely following example of Admin-on-rest (https://marmelab.com/admin-on-rest/Resource.html).
When it opens List (with DataGrid) or Show/Edit, I want to add additional components to that page. Some analytics (using Cards), Google Maps module (https://github.com/istarkov/google-map-react), Photo and etc.
I want them responsive and "floating". As different components. Not the same one.
How could I achieve this?
See the docs on how to setup a custom layout. As everything in admin-on-rest is also just react you can modify it nearly in every way you like. But notice that this requires a decent knowledge of reactand redux and probably other libraries that admin-on-rest uses under the hood. I would first try to override the standard layout. Inside your custom layout component you could e.g render any components you like at any places.
Also if you want to customize only a certain ListView you can just pass your own component to the <Ressource> component like this:
<Admin restClient={jsonServerRestClient('http://jsonplaceholder.typicode.com')}>
<Resource name="posts" list={MyCustomPostList} /* other views */ />
</Admin>
And then in /src/MyCustomPostList.js something like that:
class MyCustomPostList extends React.Component {
render() {
const {myOwnProp, ...otherProps} = this.props;
return (
<div>
// render your own components here
<AnyComponent myOwnProp={myOwnProp} />
<AGoogleMapsComponent />
// render the normal <List> component
<List {...otherProps}>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<TextField source="body" />
</Datagrid>
</List>
</div>
);
}
}
As this is not a trivial task you will not find anybody to present you a detailed solution here. You can start with the links i added and try it yourself. If you encounter any concrete problems on your way there you can come back and ask a concrete question about this.
If you want it to be responsive and floating you can use e.g. flexbox or any grid css framework.
I hope that this is a starting point for you.

Set state property from URL using react-router

I have a container component with a modal in it that is opened and closed based on a state property.
I want to control this via the URL, i.e. I want to have
/projects - the modal is NOT open
/projects/add - the modal IS open
As well as being able to link directly to it, I want the URL to change when I click on links within the main container to open the modal.
Can someone explain how I could do this, or point me in the right direction of a good tutorial?
NOTE: This way is not perfect. Even more it's rather antipattern than pattern. The reason I publish it here is it works fine for me and I like the way I can add modals (I can add modal to any page and in general their components don't depends on the other app in any way. And I keep nice url's instead of ugly ?modal=login-form). But be ready to get problems before you find everything working. Think twice!
Let's consider you want following url's:
/users to show <Users /> component
/users/login to show <Users /> component and <Login /> modal over it
You want Login to not depend on Users in anyway, say adding login modal to other pages without pain.
Let's consider you have kinda root component which stands on top of other components. For example Users render may look something like this:
render() {
return (
<Layout>
<UsersList />
</Layout>
);
}
And Layout's render may look something like this:
render() {
return (
<div className="page-wrapper">
<Header />
<Content>
{this.props.children}
</Content>
<Footer />
</div>
);
}
The trick is to force modal's injection to <Layout /> every time we need it.
The most simple approach is to use flux for it. I'm using redux and have ui reducer for such page meta-information, you can create ui store if you use other flux implementation. Anyway, final goal is to render modal if <Layout />'s state (or even better props) contains modal equal to some string representing modal name. Something like:
render() {
return (
<div className="page-wrapper">
<Header />
<Content>
{this.props.children}
</Content>
{this.props.modal ?
<Modal key={this.props.modal} /> :
null
}
<Footer />
</div>
);
}
<Modal /> returns modal component depends on given key (In case of our login-form key we want to receive <Login /> component).
Okay, let's go to router. Consider following code snippet.
const modal = (key) => {
return class extends React.Component {
static displayName = "ModalWrapper";
componentWillMount() {
// this is redux code that adds modal to ui store. Replace it with your's flux
store.dispatch(uiActions.setModal(key));
}
componentWillUnmount() {
store.dispatch(uiActions.unsetModal());
}
render() {
return (
<div className="Next">{this.props.children}</div>
);
}
}
};
...
<Route path="users" component={Next}>
<IndexRoute component={Users}>
<Route path="login" component={modal('login-form')}>
<IndexRoute component={Users} />
</Route>
</Route>
(Don't care about Next - I add it here for simplicity. Imagine it just renders this.props.children)
modal() function returns react component that triggers change in ui store. So as soon as router gets /users/login it adds login-form to ui store, <Layout /> get it as prop (or state) and renders <Modal /> which renders corresponding for given key modal.
To programmatically assess to a new URL, pass the router to your component and use push. push for example will be call in the callback trigger by the user action.
When setting your router set a route to /projects/:status. then, in your component route, you can read the value of status using this.props.param.status. Read "whats-it-look-lik" from react-router for an example.

Resources