How to create menu bar in ASP.NET - c#

I have to create a menu bar for my web application. I don't know how to create it. I came across few sites and downloaded some sample code. I have created a master page for this and pasted the code below for creating the menu which I have used.
[MethodImpl(MethodImplOptions.Synchronized)]
public override SiteMapNode BuildSiteMap()
{
// Return immediately if this method has been called before
if (_root != null)
return _root;
// Create a dictionary for temporary node storage and lookup
Dictionary<int, SiteMapNode> nodes = new Dictionary<int, SiteMapNode> (16);
// Query the database for site map nodes
using (SqlConnection connection = new SqlConnection(ConfigurationManager.AppSettings["SQLConnectionString"]))
{
connection.Open();
SqlCommand command = new SqlCommand("SELECT ID, Title, Description, Url, Roles, Parent FROM ven_sitemap ORDER BY ID", connection);
SqlDataReader reader = command.ExecuteReader ();
int id = reader.GetOrdinal("ID");
int url = reader.GetOrdinal ("Url");
int title = reader.GetOrdinal ("Title");
int desc = reader.GetOrdinal("Description");
int roles = reader.GetOrdinal ("Roles");
int parent = reader.GetOrdinal("Parent");
while (reader.Read())
{
// Create the root SiteMapNode
// Build a tree of SiteMapNodes underneath the root node
//while (reader.Read())
//{
if (reader["parent"].ToString() == "0")
{
_root = new SiteMapNode(this, reader.GetInt32(id).ToString(), reader.IsDBNull(url) ? null : reader.GetString(url),
reader.GetString(title), reader.IsDBNull(desc) ? null : reader.GetString(desc));
if (!reader.IsDBNull(roles))
{
string rolenames = reader.GetString(roles).Trim();
if (!String.IsNullOrEmpty(rolenames))
{
string[] rolelist = rolenames.Split(new char[] { ',', ';' }, 512);
_root.Roles = rolelist;
}
}
// Add "*" to the roles list if no roles are specified
if (_root.Roles == null)
_root.Roles = new string[] { "*" };
// Record the root node in the dictionary
if (nodes.ContainsKey(reader.GetInt32(id)))
throw new ConfigurationErrorsException(_errmsg2); // ConfigurationException pre-Beta 2
nodes.Add(reader.GetInt32(id), _root);
// Add the node to the site map
AddNode(_root, null);
}
else
{
SiteMapNode node = new SiteMapNode(this, reader.GetInt32(id).ToString(), reader.IsDBNull(url) ? null : reader.GetString(url),
reader.GetString(title), reader.IsDBNull(desc) ? null : reader.GetString(desc));
if (!reader.IsDBNull(roles))
{
string rolenames = reader.GetString(roles).Trim();
if (!String.IsNullOrEmpty(rolenames))
{
string[] rolelist = rolenames.Split(new char[] { ',', ';' }, 512);
node.Roles = rolelist;
}
}
// If the node lacks roles information, "inherit" that
// information from its parent
SiteMapNode parentnode = nodes[reader.GetInt32(parent)];
if (node.Roles == null)
node.Roles = parentnode.Roles;
// Record the node in the dictionary
if (nodes.ContainsKey(reader.GetInt32(id)))
throw new ConfigurationErrorsException(_errmsg2);
nodes.Add(reader.GetInt32(id), node);
// Add the node to the site map
AddNode(node, parentnode);
}
//}
}
}
// Return the root SiteMapNode
return _root;
}
protected override SiteMapNode GetRootNodeCore ()
{
BuildSiteMap ();
return _root;
}
My table :
ID Title Description Url Roles Parent
1 HOME NULL ~/Reports/Production_data_report.aspx 2 0
2 Machinename NULL ~/Reports/machine_name.aspx 3 1
3 Business Quote NULL ~/Reports/business_quote.aspx 2 1
6 Machine Counter NULL ~/Reports/machine_counter.aspx 1 0
7 Data Query NULL ~/Reports/data_query_page.aspx 2 6
8 Production Report NULL ~/Reports/yoneda_report.aspx 2 6
Output from the code:
Machine counter
Data query
Production Report
But I need to have output like this,
Home Machine counter
machinename Data query
businessquote Production Report
Where home and machine counter are root nodes. When I execute the above code my first root node is replaced by the second one.
Please help me solve this issue.

Unless you specifically need to extract the site structure from a database, I would suggest using ASP.NET Site Maps with a Web.sitemap file and then connecting it with an ASP.NET Menu Control. Your question is a little unclear so apologies if this is not what you are after.

i have used css and html to meet my requirement.. i have removed all my server side coding..
coding :
<ul id="topnav" style="left: 24px; width: 95%; position: absolute; top: 86px">
<li class ="admin" style="background-color:#FF9900; left: 0px; top: 0px;">
<h4>
ADMIN
</h4>
<div class="sub">
<ul>
<li><h2>ADD MACHINE</h2></li>
<li><h2>ADD JOB</h2></li>
</ul>
</div>
</li>
<li class ="report" style="background-color:#ff9933; left: 154px; top: 0px;">
<h4 style="background-color: #ff9933">
REPORT
</h4>
<div class="sub">
<ul>
<li style ="color:Red;"><h2>MACHINE REPORT</h2></li>
<li style="visibility:hidden;">PRODUCTION REPORT</li>
</ul>
<ul>
<li style ="color:Red;"><h2>TIME SHEET</h2></li>
<li >ASSEMBLY</li>
<li>MAINTENANCE</li>
<li>CNC</li>
<li>DESIGN</li>
</ul>
<ul>
<li style ="color:Red;"><h2>MACHINE COUNTER</h2></li>
<li>MACHINE COUNTER</li>
</ul>
</div>
</li>
<li class ="business" style="left: -100px; top: 0px; height: 38px; background-color: #ff9933" >
<h4>
BUSINESS
</h4>
<div class="sub">
<ul>
<li><h2>BUSINESS QOUTE</h2></li>
<li><h2>BUSINESS AWARD </h2></li>
</ul>
</div>
<!--
<li>
Store Locator
</li>

Related

C# Foreach goes too quickly for the webbrowser control

I am coding in C# using WindowsForms.
I am trying to iterate through a list of ID's that changes the url of a webbrowser control.
ClientID is an List<int> ClientID = new List<int>();
And filled with around 10-15 different numbers.
The foreach goes too quickly for the webbrowser control, and because of that the ErrorDiv is always null. The site isn't able to load, thus I am not able to check for the div with the specified class. If this class does exist, the foreach has to contiue with the next Client.
foreach (int Client in ClientID)
{
if(webBrowser1.ReadyState == WebBrowserReadyState.Complete)
{
webBrowser1.Navigate(URLconsult + "/" + Client);
}
var ErrorDiv = webBrowser1.Document
.GetElementsByTagName("div")
.Cast<HtmlElement>()
.FirstOrDefault(m => m.GetAttribute("className") == "incompleteConsultNotification");
Console.WriteLine(webBrowser1.Document.GetElementsByTagName("div").Cast<HtmlElement>().FirstOrDefault(m => m.GetAttribute("className") == "incompleteConsultNotification"));
//if (ErrorDiv == null)
//{
// Console.WriteLine("Normal");
//}
//else
//{
// Error.Add(Client);
// continue;
//}
}
The HTML div I try to target:
<div class="incompleteConsultNotification">
This form is incomplete. Please add the following:
<ul>
<li> option 1</li>
<li> option 2</li>
</ul>
</div>

How to implement pagination in asp.net core razor pages

I'm learning asp.net core razor pages with ef. I want to implement pagination with my table, I have check this tutorial
https://learn.microsoft.com/en-us/aspnet/core/data/ef-rp/sort-filter-page?view=aspnetcore-2.1
but it only support pre and next, I have researched for a long time, all of the solution are related to asp.net core mvc, but I'm using razor pages, there's no controller in my project, any ideas to implement?
This is the effect what I want to implement
<form method="get" asp-page="./Index">
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
#{
var totalPages = Model.Products.Count % 2 == 0 ? Model.Products.Count / 2 : Model.Products.Count / 2 + 1;
}
#for (int i = 1; i <= totalPages; i++)
{
<li><a asp-page="./Index" asp-route-id="#i">#i</a></li>
}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</form>
cshtml.cs
public async Task OnGetAsync(string sortOrder, string searchString, string shopString, string statusString, int page)
{}
Pagination is relatively simple. There's libraries available to do it for you, but I've started to find them more trouble than they're worth.
You need three pieces of information from the request (or set to default values):
Page number (default to 1)
Page size (typically defaults to 10, but whatever you want)
Sort (not strictly necessary, but you should at least order by something to keep the results consistent across pages)
The page number and size give you your "skip" and "take" values:
var skip = (page - 1) * size;
var take = size;
You can then fetch the results via:
var pageOfResults = await query.Skip(skip).Take(take).ToListAsync();
Where query is an IQueryable - either your DbSet directly or the DbSet with a Where clause, OrderBy, etc. applied.
Then, you just need to the total number of items to figure the pages:
var count = await query.CountAsync();
Pro Tip, you can parallelize the two queries (results and total count) by doing:
var resultsTask = query.Skip(skip).Take(take).ToListAsync();
var countTask = query.CountAsync();
var results = await resultsTask;
var count = await countTask;
Tasks return hot, or already started. The await keyword simply holds the continuation of the rest of the code until the task completes. As a result, if you await each line, they'll complete in serial, but if you start both, first, and then await each, they'll process in parallel.
Anyways, once you have the count:
var totalPages = (int)Math.Ceil(Decimal.Divide(count, size));
var firstPage = 1;
var lastPage = totalPages;
var prevPage = Math.Max(page - 1, firstPage);
var nextPage = Math.Min(page + 1, lastPage);
Note: you can determine whether to show first/previous and last/next buttons based on whether they equal firstPage or lastPage, respectively.
Then, just build yourself a model with this information, and you can send that to the view to render the results and generate the paging HTML.
I have created a paging taghelper for .net Core Razor Pages, it can be configured within html tags or appsettings.json to show/ hide prev-next, first-last buttons, number of max displayed pages and more customization settings are available,
Install the nuget package:
Install-Package LazZiya.TagHelpers
Add the taghelper to _ViewImports.cshtml
#addTagHelper *, LazZiya.TagHelpers
Finally add the paging control to the view:
<paging
total-records="Model.TotalRecords"
page-no="Model.PageNo"
query-string-value="#(Request.QueryString.Value)">
</paging>
[Update]
Starting from v3.1.0 query-string-value is not necessary to be passed, additonally all options is turned on by default.
<paging
total-records="Model.TotalRecords"
page-no="Model.PageNo">
</paging>
Using appsettings.json for paging configurations will help to have more clean html code and it gives the ability to change paging settings on all or some paging taghelpers by once in the application.
See live demo for all settings: http://demo.ziyad.info/en/paging
Related article:
http://ziyad.info/en/articles/21-Paging_TagHelper_for_ASP_NET_Core
I made this implementation mixing together a few answers on the subject, I hope it helps someone.
Add a PagedResultBase class (that you can extend adding other properties you need):
public abstract class PagedResultBase
{
public int CurrentPage { get; set; }
public int PageCount { get; set; }
public int PageSize { get; set; }
public int RowCount { get; set; }
}
Add a PagedResult class:
public class PagedResult<T> : PagedResultBase where T : class
{
public ICollection<T> Results { get; set; }
public PagedResult()
{
Results = new List<T>();
}
}
Add a IQueryableExtensions with a GetPagedResult extension:
public static class IQueryableExtensions
{
public async static Task<PagedResult<T>> GetPagedResultAsync<T>(this IQueryable<T> query, int currentPage, int pageSize) where T : class
{
var skip = (currentPage - 1) * pageSize;
var take = pageSize;
var rowCount = await query.CountAsync();
var results = await query.Skip(skip).Take(take).ToListAsync();
var pagedResult = new PagedResult<T> {
CurrentPage = currentPage,
PageCount = (int)Math.Ceiling(decimal.Divide(rowCount, pageSize)),
PageSize = pageSize,
RowCount = rowCount,
Results = results
};
return pagedResult;
}
}
You are done:
var pagedResult = await MyContext.Posts.Where(p => p.Featured == true).GetPagedResultAsync(1, 10);
You can use the JW.Pager NuGet package (https://www.nuget.org/packages/JW.Pager/)
Here's an example razor pages page model that paginates a list of 150 items:
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.RazorPages;
using JW;
namespace RazorPagesPagination.Pages
{
public class IndexModel : PageModel
{
public IEnumerable<string> Items { get; set; }
public Pager Pager { get; set; }
public void OnGet(int p = 1)
{
// generate list of sample items to be paged
var dummyItems = Enumerable.Range(1, 150).Select(x => "Item " + x);
// get pagination info for the current page
Pager = new Pager(dummyItems.Count(), p);
// assign the current page of items to the Items property
Items = dummyItems.Skip((Pager.CurrentPage - 1) * Pager.PageSize).Take(Pager.PageSize);
}
}
}
And here's the razor pages page containing the html for the paged list and pager controls:
#page
#model RazorPagesPagination.Pages.IndexModel
<!-- items being paged -->
<table class="table table-sm table-striped table-bordered">
#foreach (var item in Model.Items)
{
<tr>
<td>#item</td>
</tr>
}
</table>
<!-- pager -->
#if (Model.Pager.Pages.Any())
{
<nav class="table-responsive">
<ul class="pagination justify-content-center d-flex flex-wrap">
#if (Model.Pager.CurrentPage > 1)
{
<li class="page-item">
<a class="page-link" href="/">First</a>
</li>
<li class="page-item">
<a class="page-link" href="/?p=#(Model.Pager.CurrentPage - 1)">Previous</a>
</li>
}
#foreach (var p in Model.Pager.Pages)
{
<li class="page-item #(p == Model.Pager.CurrentPage ? "active" : "")">
<a class="page-link" href="/?p=#p">#p</a>
</li>
}
#if (Model.Pager.CurrentPage < Model.Pager.TotalPages)
{
<li class="page-item">
<a class="page-link" href="/?p=#(Model.Pager.CurrentPage + 1)">Next</a>
</li>
<li class="page-item">
<a class="page-link" href="/?p=#(Model.Pager.TotalPages)">Last</a>
</li>
}
</ul>
</nav>
}
For more details I posted a full tutorial with example project at http://jasonwatmore.com/post/2018/10/15/aspnet-core-razor-pages-pagination-example

How to pass List String to TempData Asp.Net

I have a Tempada to show a list of error in a msg error,i create a List and in my foreach, each error find it, i add a error in my List and later i show this list in TempData
public IActionResult Demo()
{
List<string> LogErros = new List<string>();
try
{
foreach (var item in somethings)
{
// if have some error add to list
LogErros.add();
}
if (LogErros.Count > 0)
{
TempData["error-message"] = LogErros;
}
}
return View();
}
I try this:
#if (TempData["error-message"] != null)
{
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">x</button>
#TempData["error-message"]
</div>
}
but get error
enter image description here
TempData["error-message"] stores a list of strings as an Object. So you need to get that first, cast it to a list of strings, loop through each one of them and render it.
Razor basically calls the ToString on the expression (in your case, object) and hence you are seeing your current results
This should work
#if (TempData["error-message"] != null)
{
var errors = TempData["error-message"] as List<string>;
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" >x</button>
#foreach(var errorMessage in errors)
{
<p>#errorMessage</p>
}
</div>
}
While this works, I recommend not putting a lot of C# code in the view. If it is an asp.net core project, I would recommend creating a tag helper for this. Here is a very simple one.
[HtmlTargetElement("div", Attributes = "messages")]
public class AlertMessagesTagHelper : TagHelper
{
[ViewContext]
public ViewContext ViewContext { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
StringBuilder str = new StringBuilder();
var messages = ViewContext.TempData["error-message"] as List<string>;
if (messages != null && messages.Any())
{
str.Append("<div class='alert alert-danger alert-dismissable'>");
foreach (var message in messages)
{
str.AppendFormat("<div>{0}</div>", message);
}
str.Append("</div>");
}
output.Content.AppendHtml(str.ToString());
}
}
Now in your _ViewImports.cshtml file, use the addTagHelper method to include all the tag helpers from your project
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#addTagHelper *, YourAssemblyName
Now in your view or layout, you can call this tag helper by using a div element with the messages attribute
<div messages></div>
Feel free to update the tag helper code to render the HTML markup you want for the messages.
For Non-Asp.Net core projects, you can create an html helper method which does the same thing.
The problem is you are displaying #TempData["error-message"] in your view, but TempData is essentially a Dictionary<string, object> which means when you access the value at that key, the value is an object.
Even if you cast to its actual value (List<string>) it will implicitly call .ToString(), which wont automatically display the contents of the list if you just use the # symbol to render on the page.
First thing you need to do is cast your object to a List<string>:
var errorMessageList = TempData["error-message"] as List<string>;
Then you can iterate over the values in the list:
var errorMessageList = TempData["error-message"] as List<string>;
#if (errorMessageList != null)
{
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">x</button>
#foreach(var message in errorMessageList)
{
#message
}
</div>
}
Of course you will have to format this how you want, maybe it should be comma separated? Maybe it should be in their own <span>... That is up to you.

Error "Object reference not set to an instance of an object"

This code can work with one of the web, but with some sites it back error messages like this, I do not know how to edit (Error in stars)
var document = webBrowser1.Document;
var documentAsIHtmlDocument3 = (mshtml.IHTMLDocument3)document.DomDocument;
var htmlString = documentAsIHtmlDocument3.documentElement.innerHTML;
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(htmlString);
// Sử dụng node để lấy tin
HtmlNodeCollection texts = doc.DocumentNode.SelectNodes("//div[#id='footer']/p");
string kq = "";
// cho vòng lặp để lấy kết quả
foreach (var item in texts)
{
kq += item.InnerText + Environment.NewLine;
}
richTextBox1.Text = kq;
HTML code:
<div id="divTop" >
<div id="text-conent" style="width: 500px; float: right;"></div>
<div id="grid" style="margin-removed 505px; height: 700px;"></div>
</div>
It seems that on the pages where this is successful there exists a div with the id of footer
But on other pages where this fails no such div exists.
So it seems like your logic may need to change to make the search expression that doc.DocumentNode.SelectNodes more forgiving.
Alternatively create a few more search strings that would work if your original fails:
if(texts == null){
texts = doc.DocumentNode.SelectNodes("some other search string");
}
etc.

How not to render link title with Sitecore Glass Mapper

I'm rendering Sitecore Link with this method of GlassMapper:
<li>
<%=GlassHtml.RenderLink(icon, x => x.Link, null, true, string.Empty) %>
</li>
but don't want to display Link description in Editing mode,
so even if Link description is filled it will be rendered like this:
<a href='https://url.com' class='icon-facebook' target='_blank' ></a>
and not like this:
<a href='https://url.com' class='icon-facebook' target='_blank' >Link description</a>
So I wonder if GlassHtml.RenderLink can be override for such kind of purposes? Tnx
One of the options is to add blank space for contents if the page is in editing mode. It won`t make the link empty but it won't show it's description.
<% if (IsInEditingMode)
{ %>
<li>
<%=GlassHtml.RenderLink(icon, x => x.Link, isEditable: true, contents: " ") %>
</li>
<% } else {%>
<li>
<%=GlassHtml.RenderLink(icon, x => x.Link, null, true, string.Empty) %>
</li>
<%}%>
Another option is to write your own glass extension. (For more information on how to do something like this you can see this thread - Glass Mapper RenderLink link description - default text if empty)
Glass.Mapper is open source and you can see how render link actually works here:
https://github.com/mikeedwards83/Glass.Mapper/blob/master/Source/Glass.Mapper.Sc/GlassHtml.cs (The method starts on line 297).
To extend it you will need something like this
public virtual string RenderEmptyLinkInEditing<T>(T model, Expression<Func<T, object>> field, object attributes = null, bool isEditable = false, string contents = null)
{
NameValueCollection attrs = null;
if (attributes is NameValueCollection)
{
attrs = attributes as NameValueCollection;
}
else
{
attrs = Utilities.GetPropertiesCollection(attributes, true);
}
var sb = new StringBuilder();
var writer = new StringWriter(sb);
RenderingResult result = null;
if (IsInEditingMode && isEditable)
{
if (contents.IsNotNullOrEmpty())
{
attrs.Add("haschildren", "true");
}
result = MakeEditable(
field,
null,
model,
attrs,
_context, SitecoreContext.Database, writer);
// if (contents.IsNotNullOrEmpty())
// {
// sb.Append(contents);
// }
}
else
{
result = BeginRenderLink(
field.Compile().Invoke(model) as Fields.Link, attrs, contents, writer
);
}
result.Dispose();
writer.Flush();
writer.Close();
return sb.ToString();
}

Categories