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>
}
Related
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.
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;
}
I have a custom user control ascx that exposes a simple property
/// <summary>
/// The currently selected ID, if there is one
/// </summary>
public virtual int? SelectedId
{
get { return (int)ViewState["XXID"]; }
set { ViewState["XXID"] = value; }
}
The control is inside a PlaceHolder and the value reads just fine in the postback onclick method of a button below the PlaceHolder.
However if the PlaceHolder visible=false then ViewState["XXID"] returns null. If I toggle the PlaceHolder visible=true then the value comes back.
<asp:PlaceHolder runat="server" ID="plcCustomer" >
<my:CustomPicker runat="server" ID="cboCustomer" />
</asp:PlaceHolder >
<asp:Button runat="server" ID="btnToggleVisible" onclick="btnToggleVisible_OnClick" text="Toggle visible" />
<asp:Button runat="server" ID="btnGetSelectedId" onclick="btnGetSelectedId_OnClick" text="Get Value" />
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
plcCustomer.SelectedId = 5;
}
protected void btnToggleVisible_OnClick(object sender, EventArgs e)
{
plcCustomer.Visible = !plcCustomer.Visible;
}
protected void btnGetSelectedId_OnClick(object sender, EventArgs e)
{
...
plcCustomer.SelectedId //<== this will be null whenever plcCustomer is invisible
...
}
I have a hunch that the page has not bothered loading my control's viewstate because it is not going to be visible.
If so how can I instruct the page that it should load the viewstate of custom controls even when they are in a hidden PlaceHolder?
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();
}
}
}
In my ASP.NET MVC 2 application I use HandleErrorAttribute to display a custom error page in case of unhandled exceptions, and it works perfectly unless the exception happens in an action called by Ajax.ActionLink. In this case nothing happens. Is it possible to use HandleErrorAttribute to update the target element with the contents of an "Error.ascx" partial view?
To achieve this you could write a custom action filter:
public class AjaxAwareHandleErrorAttribute : HandleErrorAttribute
{
public string PartialViewName { get; set; }
public override void OnException(ExceptionContext filterContext)
{
// Execute the normal exception handling routine
base.OnException(filterContext);
// Verify if AJAX request
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
// Use partial view in case of AJAX request
var result = new PartialViewResult();
result.ViewName = PartialViewName;
filterContext.Result = result;
}
}
}
And then specify the partial view to be used:
[AjaxAwareHandleError(PartialViewName = "~/views/shared/error.ascx")]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult SomeAction()
{
throw new Exception("shouldn't have called me");
}
}
And finally in your view assuming you have the following link:
<%= Ajax.ActionLink("some text", "someAction", new AjaxOptions {
UpdateTargetId = "result", OnFailure = "handleFailure" }) %>
You could make the handleFailure function to update the proper div:
<script type="text/javascript">
function handleFailure(xhr) {
// get the error text returned by the partial
var error = xhr.get_response().get_responseData();
// place the error text somewhere in the DOM
document.getElementById('error').innerHTML = error;
}
</script>