I am using nuget Package named ExcelDataReader in MVC application to read Excel sheet and convert it to HTML.All sounds goof but i am not able to read special character from excel sheet.For example is cell value is "59%" but its reading 0.59.So how can i get exact same string value from excel.I am using following code in Controller to read and display excel to html.
public ActionResult ViewExcelFileData(long? id, int sheetindex)
{
var excelfile = db.ExcelUpload.FirstOrDefault(x => x.FileID == id);
string filePath= string.Format(Server.MapPath("~/App_Data/ExcelUploads/Labor_Excel/") + excelfile.FileName);
System.IO.File.GetAccessControl(filePath);
FileStream stream = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read);
IExcelDataReader reader = null;
if (excelfile.FileName.EndsWith(".xls"))
{
reader = ExcelReaderFactory.CreateBinaryReader(stream);
}
else if (excelfile.FileName.EndsWith(".xlsx"))
{
reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
}
reader.IsFirstRowAsColumnNames = true;
DataSet result = reader.AsDataSet();
reader.Close();
return View(result.Tables[sheetindex]);
}
By returning datatable in View side I am using Following Code in Cshtml.
<table class="gridtable" id="table-1">
<thead class="fixed_headers">
<tr>
#foreach (DataColumn col in Model.Columns)
{
<th>#col.ColumnName</th>
}
</tr>
</thead>
<tbody>
#foreach (DataRow row in Model.Rows)
{
<tr>
#foreach (DataColumn col in Model.Columns)
{
<td>#row[col.ColumnName]</td>
}
</tr>
}
</tbody>
</table>
So is it possible in controller side or View side I can get 59% instead of 0.59?
Here is Two images in which one is belongs to excel and second is HTML.
IMAGE :1
IMAGE 2 :
ExcelDataReader currently does not expose any formatting information, it provides you with the raw values except for dates that are converted to DateTime.
There's an open issue about extending it to provide formatting information, https://github.com/ExcelDataReader/ExcelDataReader/issues/215.
Instead of using the AsDataSet() method, you could read the row one by one and read the value as string. Drawback for this is you need to specify the columns one by one which is a maintainability issue.
while (reader.Read())
{
var value = reader.GetString(0); //Get value of first column
}
I suspect that the AsDataSet() converts the data to its respective data type that's why you are seeing the converted decimal value instead of the actual value in the excel.
Related
For context, I'm using ABP.IO/Blazorise to show a bunch of transactions.
Aggregate data is returned by from a serverside call. All works well, except for the alignment of those columns. They are 'something' aligned it seems... I would like the correctly right aligned with the other values in the grid rows.
Here's a pic of what it looks like:
And here is the code:
<DataGrid
Striped="true"
TItem="ViewTransactionDetailedDto"
Data="TransactionsList"
AggregateData="AggregatesList"
ReadData="OnDataGridReadAsync"
TotalItems="#TotalCount"
CurrentPage="#CurrentPage"
PageSizeChanged="#OnPageSizeChanged"
ShowPager="true"
ShowPageSizes="true"
Sortable="true"
PageSize="#PageSize">
<DataGridAggregates>
#foreach (var aggregate in ThisReportGridColumns.AggregateColumns)
{
<DataGridAggregate Field="#(aggregate.field)" Aggregate="DataGridAggregateType.Sum" DisplayFormat="{0:N0}"></DataGridAggregate>
}
</DataGridAggregates>
<DataGridColumns>
#{ int index = 0; }
#foreach (var col in ThisReportGridColumns.Columns)
{
var colRefTemplate = col.custom;
if (!col.HasCustomLookup)
{
<DataGridColumn TItem="ViewTransactionDetailedDto"
DisplayOrder="#index"
Field="#(col.field)"
Sortable="#col.sortable"
SortField="#col.sortField"
Caption="#col.caption"
HeaderTextAlignment="#col.BlazorHeaderAlignment()"
TextAlignment="#col.BlazorTextAlignment()">
</DataGridColumn>
}
#if (col.HasCustomLookup)
{
<DataGridColumn TItem="ViewTransactionDetailedDto"
DisplayOrder="#index"
Field="#col.field"
Sortable="#col.sortable"
SortField="#col.sortField"
Caption="#col.caption"
HeaderTextAlignment="#col.BlazorHeaderAlignment()"
TextAlignment="#col.BlazorTextAlignment()">
<DisplayTemplate>
#context.ValueForRefWithName(colRefTemplate)
</DisplayTemplate>
</DataGridColumn>
}
index++;
}
</DataGridColumns>
</DataGrid>
The columns are dynamic, since there are a couple of report layouts.
But the values returned (for column alignment) are the same as in Blazorise.
There doesn't seem to be a way to specify horizontal alignment in a DataGridAggregate.
Ideas?
#Html.DisplayFor(modelItem => item.Quantity)*(modelItem => item.PartsPrice)
I can display 1 or both item but unable to multiply any easy solution for above situation?
Create Price property in your modal as shown below than after use of Price property to display multiplication in your view page.
Price property declaration in modal.
public decimal Price
{
get
{
return Quantity * PartsPrice;
}
}
Display in razor view page as follow.
#Html.DisplayFor(modelItem => item.Price)
Hope it will be helpful.
You can not calculate like that. You can calculate in model, otherwise if you want to calculate the values in view, you can try the following
#{
var result = Model.Quantity * Model.PartsPrice; // Calculate the price
<span>#result</span>
}
#result will display the calculated value
if suppose the model is collection then, use foreach loop
#{
foreach (var item in Model)
{
var result = item.Quantity * item.PartsPrice; // Calculate the price
<span>#result</span>
}
}
A common way to fill a table is:
#For Each item In Model
Dim currentItem = item
#<tr>
<td>currentitem.Data1</td>
<td>currentitem.Data2</td>
<td>currentitem.Data3</td>
</tr>
Next
But for some reasons (to control the order of columns), I would like to refer to the fields by their string names, something like this:
#For Each item In Model
Dim currentItem = item
#<tr>
<td>currentitem("Data1").Value</td>
<td>currentitem("Data2").Value</td>
<td>currentitem("Data3").Value</td>
</tr>
Next
Is it somehow possible?
Ok - now that we have established that you need to change the order of your view model, let's do a little bit of work to your view model to make it easier to change the order. Given that we have to change the order of how we display things, we have to have a way to track what order to display them in. To change on the fly in the view without having different views with different orders (could get messy fast) - so let's just update our model a little bit.
Let assume this is your view model
public class OriginalViewModel{
public string Data1 {get;set;}
public string Data2 {get;set;}
public string Data3 {get;set;|
}
Let's create a new class called DataProperty. This will hold the data objects as well as allow us to set a display order that we can sort on later.
public class DataProperty{
public int DisplayOrder {get;set;}
public string Data {get;set;}
}
Now, let's update your view model to be a set of these DataProperties. We are using something we can enumerate and order by the display order.
public class UpdatedViewModel{
public IEnumerable<DataProperty> DataSet {get;set;}
}
Now, you can set the display order on each one of your property elements.
var listOfItems = new List<DataProperty>();
listOfItems.Add(new DataProperty{Data = "data1", DisplayOrder = 2});
listOfItems.Add(new DataProperty{Data = "data2", DisplayOrder = 3});
listOfItems.Add(new DataProperty{Data = "data3", DisplayOrder = 1});
var model = new UpdatedViewModel();
model.Data = listOfItems;
In your view, order by the display order property. Note we can now use Linq to order our data appropriately based on the requirements for this view.
#{foreach(var item in Model.OrderBy(x=>x.Data.DisplayOrder){
<tr>
<td>#item.Data</td>
<td>#item.Data</td>
<td>#item.Data</td>
</tr>
}}
which should render in HTML
<tr>
<td>data3</td>
<td>data1</td>
<td>data2</td>
</tr>
Thank you Tommy,
I tried to solve it in simple way and did this:
For example, I have a Viewdata that contains the order of the columns:
ViewData("columnsorder")="|3|1|2|"
and then, I just loop through ViewData and set the columns.
#For Each item In Model
Dim currentItem = item
#<tr>
#For i As Integer = 1 To ViewData("columnsorder").ToString.Split("|").Count - 2
Dim ind As Integer = ViewData("columnsorder").ToString.Split("|")(i)
Select Case ind
Case 1#<td>#currentItem.Data1</td>
Case 2#<td>#currentItem.Data2</td>
Case 3#<td>#currentItem.Data3</td>
End Select
Next
</tr>
Next
I'm trying to create a WebGrid which has to be very dynamic. The columns are defined in a list, which I've done like so:
#{
List<WebGridColumn> columns = new List<WebGridColumn>();
foreach (var column in Model.Columns)
{
columns.Add(new WebGridColumn() { ColumnName = column.Name, Header = column.Name });
}
}
#grid.GetHtml(
columns: columns)
All well and good, but the problem I have is with the rows. I'll try and explain...
For this question let's say we have two columns for Name and Address.
I have a collection of row objects, lets say SearchResult objects. A SearchResult contains a Dictionary of any number of attributes, such as Name, Address, Phone, Height, Bra Size, or anything (think of the EAV pattern). I need to access the attributes based on Column Name.
I figured I could do this using format, but I can't seem to figure it out. I want something like this:
columns.Add(new WebGridColumn() { ColumnName = column.Name, Header =
column.Header, Format = #<text>#item.Attributes[column.Name]</text> });
This sort of works but despite creating the format for the separate columns, the rows get populated with only the last column's format. i.e.:
Name Address
1 Main Street 1 Main Street
45 Paradise Av 45 Paradise Av
etc
I think it should work if you leave out the "ColumnName" (superfluous anyway), and also make the dynamic expression a bit more explicit:
columns.Add(
new WebGridColumn() {
Header = column.Header,
Format = (item) => #Html.Raw("<text>" + #item.Attributes[column.Name] + "</text>")
}
);
This issue is related to reference variables. You need to have the Format property in terms of the other properties of the WebGridColumn. This is how I would do it:
#{
List<WebGridColumn> columns = new List<WebGridColumn>();
foreach (var column in Model.Columns)
{
var col = new WebGridColumn();
col.Header = column.Name;
col.Format = (item) => #Html.Raw("<text>" + #item.Attributes[col.Header] + "</text>");
columns.Add(col);
}
}
All,
I've read through a lot of posts about Checkboxes and ASP.MVC but I'm not that much wiser.
My scenario:
I have a strongly typed View where I pass a collection of summary objects to the view for rendering in a for-each. This summary object contains label data based on a unique id. I also add a checkbox to the row so do so via:
<td>
<%= Html.CheckBox("markedItem", Model.MarkedItem, new { TrackedItemId = Model.Id })%>
</td>
When I perform a POST to get the submitted results my action method takes the strongly typed ViewModel back but the original summary object that I used to create the list is not populated.
Ok, this is annoying, but I can understand why so I'll live with it.
What I then do is to add a new property to my ViewModel called "MarkedItem" which is a string collection.
On postback this marked item is filled with the before and after states if the checkbox has changed but nothing to tell me which key they were for. Just to clarify, if I send this
TrackedItemId = A, Value = false
TrackedItemId = B, Value = true
TrackedItemId = C, Value = false
and set the page to this:
TrackedItemId = A, Value = true
TrackedItemId = B, Value = true
TrackedItemId = C, Value = false
I will get back this:
MarkedItem[0] = true
MarkedItem[1] = false
MarkedItem[2] = true
MarkedItem[3] = false
in other words [0] is the new value and [1] is the old value, [2] and [3] represent values that haven't changed.
My questions are:
Is this right - that I get before and after in this way? Is there any way to only send the latest values?
How can I get hold of the custom attribute (TrackedItemId) that I've added so that I can add meaning to the string array that is returned?
So far I like MVC but it not handling simple stuff like this is really confusing. I'm also a javascript noob so I really hope that isn't the answer as I'd like to return the data in my custom viewmodel.
Please make any explanations/advice simple :)
<p>
<label>
Select project members:</label>
<ul>
<% foreach (var user in this.Model.Users)
{ %>
<li>
<%= this.Html.CheckBox("Member" + user.UserId, this.Model.Project.IsUserInMembers(user.UserId)) %><label
for="Member<%= user.UserId %>" class="inline"><%= user.Name%></label></li>
<% } %></ul>
and in the controller:
// update project members
foreach (var key in collection.Keys)
{
if (key.ToString().StartsWith("Member"))
{
int userId = int.Parse(key.ToString().Replace("Member", ""));
if (collection[key.ToString()].Contains("true"))
this.ProjectRepository.AddMemberToProject(id, userId);
else
this.ProjectRepository.DeleteMemberFromProject(id, userId);
}
}
With thanks to Pino :)
ok, one hack I've come up with - I really hate that I have to do this but I don't see another way round it and I'm sure it will break at some point.
I've already implemented by own ModelBinder to get round some other issues (classes as properties for example) so have extended it to incorporate this code. We use Guid's for all our keys.
If there are any alternatives to the below then please let me know.
Html
<%= Html.CheckBox("markedItem" + Model.Id, false)%>
C#
(GuidLength is a const int = 36, Left and Right are our own string extensions)
//Correct checkbox values - pull all the values back from the context that might be from a checkbox. If we can parse a Guid then we assume
//its a checkbox value and attempt to match up the model. This assumes the model will be expecting a dictionary to receive the key and
//boolean value and deals with several sets of checkboxes in the same page
//TODO: Model Validation - I don't think validation will be fired by this. Need to reapply model validation after properties have been set?
Dictionary<string, Dictionary<Guid, bool>> checkBoxItems = new Dictionary<string, Dictionary<Guid, bool>>();
foreach (var item in bindingContext.ValueProvider.Where(k => k.Key.Length > GuidLength))
{
Regex guidRegEx = new Regex(#"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$");
if (guidRegEx.IsMatch(item.Key.Right(GuidLength)))
{
Guid entityKey = new Guid(item.Key.Right(GuidLength));
string modelKey = item.Key.Left(item.Key.Length - GuidLength);
Dictionary<Guid, bool> checkedValues = null;
if (!checkBoxItems.TryGetValue(modelKey, out checkedValues))
{
checkedValues = new Dictionary<Guid, bool>();
checkBoxItems.Add(modelKey, checkedValues);
}
//The assumption is that we will always get 1 or 2 values. 1 means the contents have not changed, 2 means the contents have changed
//and, so far, the first position has always contained the latest value
checkedValues.Add(entityKey, Convert.ToBoolean(((string[])item.Value.RawValue).First()));
}
}
foreach (var item in checkBoxItems)
{
PropertyInfo info = model.GetType().GetProperty(item.Key,
BindingFlags.IgnoreCase |
BindingFlags.Public |
BindingFlags.Instance);
info.SetValue(model, item.Value, null);
}