MAUI Blazor App - Run Code On Any Page Load? - maui

Is it possible to run a piece of code on every time a page is loaded whether its being navigated to or any other scenario it may be?
Something like overriding OnNavigate method?

You can override OnAppearing method in the .xaml.cs code of the page, and add a piece of code specified to OnAppearing. OnAppearing means that when the page appears, it will be called.
public partial class Page : ContentPage
{
public Page()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
//a piece of code specified
}
}

I thing that you can use also "Loaded" event:
Add the line Loaded="Page_Loaded" to your ContentPage XAML, like
this:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...
Loaded="Page_Loaded"
>
Add "Page_Loaded" event code to your page code-behind (.cs) file:
private async void Page_Loaded(object sender, EventArgs e)
{
<Your code here>
}
I hope this helps.

An option for when you have both your HTML and your C# code in your .razor file is overwriting the OnInitialized method:
#page "/location"
<h1>Page Title</h1>
#if (items == null)
{
<p>No loadable data</p>
}
#else
{
#foreach (var item in items)
{
<p>#item.Title</p>
}
}
#code {
private List<Class> items;
protected override void OnInitialized()
{
// Load items here
base.OnInitialized();
}
}
This approach is not recommended when you do it for multiple pages, in that case use Jianwei's approach.

Related

Xamarin Forms UWP PageRenderer

i got some troubles with using the PageRenderer.
MainPage.xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="abc.CustomView">
<ContentPage.Content>
<StackLayout>
<Button Text="scann" Clicked="BtnScannClicked"></Button>
</StackLayout>
</ContentPage.Content>
MainPage.cs
async void BtnScannClicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new CustomView());
}
CustomView.Xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="abc.CustomView">
<ContentPage.Content>
</ContentPage.Content>
</ContentPage>
CustomView.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomView : ContentPage
{
public CustomView ()
{
InitializeComponent ();
}
}
DemoPage.cs (which is my CustomRenderer)
[assembly: ExportRenderer(typeof(CustomView), typeof(DemoPage))]
namespace abc.UWP
{
class DemoPage: PageRenderer
{
Page page;
Application app;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
try
{
app = Application.Current;
SetupUserInterface();
this.Children.Add(page);
}
catch (Exception ex)
{
Debug.WriteLine(#" ERROR: ", ex.Message);
}
}
void SetupUserInterface()
{
var stackPanel = new StackPanel();
page = new Page();
page.Content = stackPanel;
}
}
}
There is always a
Exception thrown: 'System.InvalidOperationException' in Xamarin.Forms.Platform.UAP.dll
error during the build.
But I guess this is not really a problem with the PageRenderer. Seems that this appears during the ClickEvent.
There is always a Exception thrown: 'System.InvalidOperationException' in Xamarin.Forms.Platform.UAP.dll error during the build.
The problem is that you have not add the MainPage to NavigationPage.
The PushAsync method is not supported globally on Windows. You could add the the following code to the app.xaml.cs file to solve the issue.
public App()
{
InitializeComponent();
var RootNav = new NavigationPage(new MainPage());
MainPage = RootNav;
}
PushModalAsync - Push a page into a modal context. This will create a new, independent, Navigation context within the application. The modal that is created can be dismissed with a hardware back button; there appears to no way to stop this functionality.
So the PushModalAsync method does not depend on NavigationPage, it will work in your current scenario.
Put my application is always crashing (has exit code -1) after the navigation to DemoPage.cs. The Implementation should be ok, or not?
I have found that you have not implemented ArrangeOverride method in your PageRenderer. And you will not see the content of page.
protected override Size ArrangeOverride(Size finalSize)
{
page.Arrange(new Windows.Foundation.Rect(0, 0, finalSize.Width, finalSize.Height));
return finalSize;
}

Spotfire Redirecting to home after link click

Ask: Have a button that when clicked downloads a file from a folder on the server and remains on the current page.
Current state and problem: I have a CustomWizardPromptControlPage that writes a simple button to the HTMLTextWriter. The onclick event for the button fires off a window.open(urlToDocument, '_blank'). By doing the button with the onclick it does actually allow me to download the file, however the parent page redirects to the home page.
Already tried: href - didn't download the file and redirected me to the home page. form submit - didn't do anything.
If anyone can give me some insight as to why Spotfire does this and what I can do to stop it from happening it would be greatly appreciated
--Follow up with working code sample for comments request
namespace ACompanyName.SpotFire.ExportWithFilters
{
public class ExportWithFiltersWebPromptControl : CustomWizardPromptControl
{
public ExportWithFiltersWebPromptControl(ExportWithFiltersFileSettings settings)
{
this.AddPage(new ExportWithFiltersPage(settings));
}
private class ExportWithFiltersPage : CustomWizardPromptControlPage
{
private readonly ExportWithFiltersFileSettings _settings;
public ExportWithFiltersPage(ExportWithFiltersFileSettings settings) : base("Export with Filters")
{
_settings = settings;
}
protected override void OnGetContentsCore(HtmlTextWriter writer)
{
var domain = "https://dev.AURL.com";
var filename = _settings.ExportWithFiltersFileInfo.Name;
var fullFilePath = string.Format("{0}/{1}/{2}", domain, "Exports", filename);
writer.WriteLine("Download Export with Filters", fullFilePath);
}
protected override void OnGetScriptsCore(StringBuilder builder)
{
}
protected override void OnLeavePageCore(FormData data)
{
}
protected override bool OnValidatePromptCore(FormData data)
{
return true;
}
}
}
}
Turned out that Spotfire didn't like putting <button> into the page. Swapped it out with an hyperlink with a target of blank and it worked like a charm. If a button is still desired, stylized div should do the trick.

MVC 5 - Pass object to a shared view

I am developing a MVC 5 internet application and have a question in regards to passing an object to a shared view.
I have a view called CustomError.cshtml in the shared folder. This view has the following model type: #model CanFindLocation.ViewModels.CustomErrorViewModel
How can I pass an object of type CanFindLocation.ViewModels.CustomErrorViewModel to this view from the protected override void OnException(ExceptionContext filterContext) function in a controller?
Here is my code:
protected override void OnException(ExceptionContext filterContext)
{
Exception e = filterContext.Exception;
if (e is HttpRequestValidationException)
{
filterContext.ExceptionHandled = false;
customErrorViewModel = customErrorService.GetDefaultCustomError(customErrorType, "Test message.");
RedirectToAction("CustomError", customErrorViewModel);
}
}
Instead of the view being shown, the following function is called:
protected void Application_Error(object sender, EventArgs e)
Thanks in advance.
I don't think you can return view as you want, so I usually put values into TempData and make a redirection to homepage or whatever landing page.
Homepage check is there is value into this Viewbag and show error if there is error.
Controller:
public class BaseController : Controller
{
protected void SetError(string message, params object[] args)
{
TempData["UIError"] = string.Format(message, args);
}
}
In in my shared (master) layout view:
#if (TempData["UIError"] != null)
{
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
#TempData["UIError"]
</div>
}

printdialogue from view model in wpf

I have a requirement as follows, I want to print the screen elements present on the screen to printer. Implementation is done through MVVM. so If I click on print button on the screen it should display a print dialogue and selecting the printer should proceed with printing all the UI elemnts with their data . I have tried with solution present at print WPF visual from viewmodel but its missing the margings and not displaying properly
Also I have another button Print Preview which should display print preview dialogue to see the preiview.
Thanks in advance.
Regards,
Krishna.
In my opinion the printing of the View in an MVVM application is not the responsiblity or concern of the ViewModel. I believe you are better of doing this from the View.
How I've achieved this before is to use a WPF Behavior on a button - I use a Behavior because I'm using DataTemplates for the View and there isn't a 'code behind' file.
The Behavior exposes a DependencyProperty, this is a binding to what is to be printed or contains what is going to be printed.
XAML:
<Button Margin="0,2,5,2"
HorizontalAlignment="Right"
Content="PRINT"
ToolTip="Prints the current report">
<i:Interaction.Behaviors>
<b:ReportPrintClickBehavior Content="{Binding ElementName=SelectedReportContent, Mode=OneWay}" />
</i:Interaction.Behaviors>
</Button>
To reference the Behavior in the XAML you'll need to reference System.Windows.Interactivity, this can be found on NuGet here.
Code-Behind (Behavior):
In this case I'm printing a FlowDocument hosted inside a FlowDocumentReader.
public sealed class ReportPrintClickBehavior : Behavior<Button>
{
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content",
typeof(DependencyObject),
typeof(ReportPrintClickBehavior),
new PropertyMetadata(null));
public DependencyObject Content
{
get { return (DependencyObject)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += OnLoaded;
AssociatedObject.Unloaded += OnUnloaded;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Loaded -= OnLoaded;
AssociatedObject.Unloaded -= OnUnloaded;
}
private void OnLoaded(object sender, RoutedEventArgs args)
{
AssociatedObject.Click += OnClick;
}
private void OnUnloaded(object sender, RoutedEventArgs args)
{
AssociatedObject.Click -= OnClick;
}
private void OnClick(object sender, RoutedEventArgs args)
{
var flowDocumentReader = Content.GetVisualDescendent<FlowDocumentReader>();
if (flowDocumentReader != null)
{
flowDocumentReader.Print();
}
}
}

mvvmcross custom binding to eventhandler

I am trying to implement LongClick functionality on a view and read the following which provided some info
mvvmcross touch command binding in android
Searched unsuccessfully for IMvxCommand within the code so assume this may be outdated? So I attempted a best effort but cannot get any LongClick functionality - probably due to limited knowledge of C# and eventhandlers. I implemented the following but was not sure of the MvxRelayCommand usage.
public class LongClickEventBinding: MvxBaseAndroidTargetBinding
{
private readonly View _view;
private MvxRelayCommand<JobJob> _command;
public LongClickEventBinding(View view)
{
_view = view;
_view.LongClick += ViewOnLongClick;
}
private void ViewOnLongClick(object sender, View.LongClickEventArgs eventArgs)
{
if (_command != null)
{
_command.Execute();
}
}
public override void SetValue(object value)
{
_command = (MvxRelayCommand<JobJob>)value;
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_view.LongClick -= ViewOnLongClick;
}
base.Dispose(isDisposing);
}
public override Type TargetType
{
get { return typeof(MvxRelayCommand<JobJob>); }
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.OneWay; }
}
}
And
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
base.FillTargetFactories(registry);
registry.RegisterFactory(new MvxCustomBindingFactory<View>("LongClick", view => new LongClickEventBinding(view)));
}
And
public ICommand JobSelectedCommand
{
get { return new MvxRelayCommand<JobJob>(NavigateToJobTasks); }
}
public void NavigateToJobTasks(JobJob jobJob)
{
RequestNavigate<JobTaskListViewModel>(new { key = jobJob.JobID });
}
And
<Mvx.MvxBindableListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
local:MvxBind="{'ItemsSource':{'Path':'GroupedList'},'LongClick':{'Path':'JobSelectedCommand'}}"
local:MvxItemTemplate="#layout/listitem_job_old"/>
However when I run code on the emulator and LongClick mouse button on listitem not much happens.
Does the following need to be implemented in the View
public event EventHandler<View.LongClickEventArgs> LongClick;
Any help / pointers appreciated.
For lists, vNext MvxBindableListView has supported ItemLongClick for a while anyway - see
https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Binding.Droid/Views/MvxBindableListView.cs#L77
Note that this binding hooks into the ListView's ItemLongClick rather than into LongClick
Using this in your axml, you should be able to just do:
<Mvx.MvxBindableListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
local:MvxBind="{'ItemsSource':{'Path':'GroupedList'},'ItemLongClick':{'Path':'JobSelectedCommand'}}"
local:MvxItemTemplate="#layout/listitem_job_old"/>
If this doesn't work then please fire a bug report on Github issues.
If you wanted to do your custom binding on a generic (non list) View, then your code would need to switch to ICommand instead of IMvxCommand, and you also couldn't really pass in the Item argument - so you'd need to just use MvxRelayCommand on the ViewModel.
I've added View-level LongClick support to the issues list - https://github.com/slodge/MvvmCross/issues/165
But for a ListView it is probably the ItemLongClick you are actually interested in