Struggling on in my first MVC project, I need to show a menu of steps for a wizard. The problem is that some of the steps depend on the data that the user provides.
So say for example, if a user pays cash, we skip the page that shows bank-account information (and thus remove the menu-item)..
I have a "page" class in C#, and a "menu" class that has a list of "pages". I'm going to write the logic that dictates whether or not to show a menu-item in the menu class.
The problem is this;
The page class is a very simple class that looks like this ("active" means the menuitem is highlighted as the currently active item):
public class Page
{
MvcHtmlString Link { get; set; }
bool Active { get; set; }
bool Visible { get; set; }
public Page(MvcHtmlString link)
{
Link = link;
Active = false;
Visible = true;
}
public Page(MvcHtmlString link, bool active, bool visible)
{
Link = link;
Active = active;
Visible = visible;
}
}
In my logic I want to add pages to the list, and I'd like to use the "Link" property of a page to store the target URL for each menu-item. This way I can fill that property using Html.Actionlink() and all its available parameters to generate the HTML for the link.
In the eventual menu I can just iterate and show the items.
It also has the advantage that I could do an AJAX call to this function and receive HTML back I can use in my page to update the menu dynamically.
However, Html.ActionLink is not available, and in other posts on Stackoverflow I found that people also dislike using a html helper outside of an MVC view, for understandable reasons.
So my question is; how would I go about this in a clean solution? I considered giving the page class not a Link property, but "controller" and "action" properties, but I would be missing out on the flexibility of adding a class or other HTML attributes easily, which the actionlink DOES provide.
Thanks,
Erik
Related
My Question:
In Xamarin.Forms 4.2+, can I suspend the App Shell in any way while I am manipulating it? Or can I suspend the whole UI layouting and rending for an instance?
My Situation:
I am creating an App with Xamarin.Forms where I use the new Shell Navigation. Cause I change the Flyout Menu during app runtime, I want to add and remove some of the FlyoutItem by code.
As an example, I have a LoginPage which I want to replace by a UserProfilePage in the App Menu (Flyout Menu). I always have an AppInfoPage in the menu.
Whenever I remove a FlyoutItem, Shell wants to display the next item. So when I remove the LoginPage, Shell displays AppInfoPage or at least calls the constructor and executes the overload of OnAppearing on the AppInfoPage. OnAppearing then does a lot of things to prepare the App info, which is not needed now cause the page will be OnDisappearing just a few ticks later.
Most UI frameworks have some function like this to avoid unneeded UI layouting and rendering. I tried setting IsVisible = false, IsBusy = true and calling BatchBegin(), but none of them helped me.
Code Example:
Check this simplified example, see the TODOs.
private static void SyncAppShell()
{
try {
// TODO Here I want to disable the automatic "navigation on menu modification"
Current.Items.Add(CreateFlyoutItem($"{flyoutIdPrefix}-{nameof(LoginPage)}",
resources[nameof(AppStrings.LoginPage)],
NavigationConstants.LoginPage,
new LoginPage()));
Current.Items.Add(CreateFlyoutItem($"{flyoutIdPrefix}-{nameof(AppInfo)}",
resources[nameof(AppStrings.AppInfo)],
NavigationConstants.AppInfo,
new AppInfo()));
Current.Items.Remove(_staticReferenceToLogoutPage);
}
finally
{
// TODO Here I want to enable the automatic "navigation on menu modification"
}
}
private static FlyoutItem CreateFlyoutItem(string id, string title, string route, ContentPage page, bool isEnabled = true)
{
var flyoutItem = new FlyoutItem { Title = title, StyleId = id, IsEnabled = isEnabled };
flyoutItem.Items.Add(new ShellContent { Route = route, Content = page });
return flyoutItem;
}
I've got an MVC CORE/Entity Framework CORE project with some Razor pages. On the Razor pages, if I've got the same page open in two tabs/browsers, changing the inputs on one, change the inputs on the other. So, if in one tab I'm editing book 345
http://localhost:12345/books/edit/345
and in another I'm editing 456
http://localhost:12345/books/edit/456
if I'm editing the Title text box on 345, as I type, the same values are echoed on the Title text box on 456. The same is true for all inputs, drop downs, text/numeric input boxes, checkboxes, etc. Saving commits whatever's in the inputs to the record.
Any ideas why? I've not added any code as I'm not sure which'd be most relevant and don't want to dump the entire project here.
Edited for code based on comments
private readonly MyModels.MyContext _context;
public EditModel(MyModels.MyContext context) : base(context) {
_context = context;
}
[BindProperty]
public BookModel objRecord { get; set; }
This is the top of the Razor page's code behind, with the constructor and bound property
#page "{BookID?}"
#model myProject.Pages.Books.EditModel
This is the top of the .cshtml page.
In startup.cs
in
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ForceGateway.Models.ForceGatewayContextModel contextM) {
I've got
if (env.IsDevelopment()) {
app.UseBrowserLink();
UseBrowserLink links browsers to each other as well as to Visual Studio t'would appear.
My application is in MVVM architecture.
I Have photo.xaml page in which i have one 1 ListView whoose bindingcontext is ObservableCollection listphoto of photos which is defined in its viewmodel.cs file.
now i have to redirect to BarcodeScan.cs from button click of photo.xaml .
my que i how can i add item to listphoto from here(BarcodeScan.cs )??
I tried to define new list in BarcodeScan like this
public ObservableCollection<JobPhoto> ListSerialNumbers { get; set; }
and intialised in its constructor like this
ListSerialNumbers = new ObservableCollection<JobPhoto>();
but it dont update list on photo.xaml page.
how can i achieve this. I am new to MVVM.Please Help.
Thank you.
You should use messaging center for this
First get it method registered as :
MessagingCenter.Subscribe<YourObjectClassComesHere>(this, "Any Message or empty string will be okay", (Obj) =>
{
//Code you want to execute
});
After this you can invoke it from another page as
MessagingCenter.Send(YourObject(of type "YourObjectClassComesHere"), "Any Message or empty string will be okay");
Hope it helps.
More details are available at : https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/messaging-center/
You can try MessageCenter https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/messaging-center/
In Phonepage you subscript message and send a message from another page.
I Have photo.xaml page in which i have one 1 ListView whoose bindingcontext is ObservableCollection listphoto of photos which is defined in its viewmodel.cs file.
Firstly it would be worth showing your XAML code.
You say in the quote above that you set the bindingcontext of the listview to the collection. You should be setting the ItemSource property of the ListView to the collection.
Hi I am new to glassmapper and i am trying to create a simple view rendering.
While the view works, i am not able to edit it in experience editor. Is there like a setting that i should turn on???
My View is as simple is this:
#inherits Glass.Mapper.Sc.Web.Mvc.GlassView<sample.Web.Models.sampleclass>
#if (Model != null)
{
<div>
#Editable(Model,x=>x.Title)
</div>
}
My Modal:
using Glass.Mapper.Sc.Configuration.Attributes;
using System;
namespace Sampple.Web.Models.Sampleclass
{
[SitecoreType(TemplateId = "{FE05DA0F-7E18-47F8-AB77-F0ED7A0F9F90}",AutoMap = true)]
public class Sampleclass
{
[SitecoreId]
public virtual Guid Id { get; set; }
public virtual string Title{ get; set; }
[SitecoreField("Page Content")]
public virtual string Body{ get; set; }
}
}
I am able to see the content. It just that it is not editable when i open
http://mysite/?sc_mode=edit
Sidenote: i have changed the class names for explanation. Please ignore any typos
I this fixed?
If not, try below options:
When you open Sitecore Item in Experience Editor and when clicked on any field you must see those fields highlighted as in below screen shots, Then try to edit it within that highlighted area
Screen Shot 1
Screen Shot 2
if you are at the right place and if it is till not working. Can you check Sitecore Logs if there are any errors recorded.
Looking at the code it looks like you missed to map "Title" field.
I'm writing an MVC 3 app and I have tried to code a control in the Controller (due to permissions, different menu items will be visible for different users) and use the object in the Razor page. For example, in the Controller I do something like:
public ActionResult Index()
{
var menu = "#(Html.Telerik().Menu().Name("menu").Items("menus => { menus.Add().Text("Home").Action("Index", "Home"); menus.Add().Text("Deliveries").Action("Index", "Delivery"); }))";
var model = new MenuModel()
{
Menu = menu
};
return View(model);
}
And in the View I try to render the Menu using #Model.Menu but I just get the string value rather than an actual menu. Is what I'm trying to do possible?
Extend the HtmlHelper class and use the newly created method to render your menu in the View:
Helper:
public static string RenderMenu(this HtmlHelper html)
{
var menu = new StringBuilder();
/* ... menu rendering logic ... */
return menu.ToString();
}
View:
#Html.RenderMenu();
Nevertheless, it is fine to put this logic in the view. Using the HtmlHelper extension just separates/cleans the code.
I wouldn't want to do it that way even if it were possible!
You should decouple your controller and view more than you are currently doing.
The controller should only pass data the view requires. If the view needs a menu with different menu items then use the controller to decide what menu items the view should have then add them to a list object and pass that list to the view. The view will then build a menu based on the list of menu items.
Also when I say "menu items" I don't mean markup! I mean create a new MenuItemViewModel object to persist your data between your controller and your view e.g pseudo code:
public class MenuItemViewModel { string url, string text }
List<MenuItemViewModel> menuitems ...
return View(menuitems)
Why would you want to do this? This is breaking the separation of concerns in MVC - your controller shouldn't worry about how the menu is displayed, just getting the right data to the view for display.
If you want to do security trimming, don't pass in a builder string. There are other methods available.
You could try the MVC SiteMap provider which can handle security trimming against the [Authorize] controller attributes (bit of work to learn and setup, but great once its there).
Pass in your own collection of flags or pre-build menu items, like what Greg suggested.
Make a HtmlHelper extension, something like 'IsAuthorized()' that will check against the controller authorize attributes. Here's a gist of one I used to use before switching to the MVC Sitemap.
With the html helper, you can do this:
#(Html.Telerik().Menu()
.Name("Menu")
.Items(m =>
{
#* Publicly Accessible Controller *#
m.Add()
.Text("Home").Url(Url.Action("Index", "Home"));
#* Secure Controller *#
if (Html.IsAuthorized<MyProject.Controllers.SecureController>(c => c.Index()))
{
//m.Add()....
}
.....