EPPlus: Create hyperlink for column - c#

I am unable to make a hyperlink in the excel template. I'd like to display the value in the cell like this http://www.diamondschool/{personName}
I have read the official documentation on github. No luck at all
public FileInfo GenerateTemplate(long shoolId)
{
using (var excelPackage = new ExcelPackage(dataTemplate))
{
excelPackage.Workbook.Worksheets.Add("Sheet1");
var ws = excelPackage.Workbook.Worksheets[1];
var dataTable = InitializeDataTable();
var templateData = GetTemplateData(schoolId);
PopulateData(templateData, dataTable);
ws.Cells["A2"].LoadFromDataTable(dataTable, true);
}
// Since I am already loading the data from the data table I can't find a way to display the value as a hyperlink.
//http://www.diamondschool/{personName} so depending the value in the cell, display the personame as hyperlink to that address
//Person name as HyperLink
var namedStyle = ws.Workbook.Styles.CreateNamedStyle("HyperLink");
namedStyle.Style.Font.UnderLine = true;
namedStyle.Style.Font.Color.SetColor(Color.Blue);
ws.Cells["A2"].Value
ws.Cells["A2"].StyleName = "HyperLink";
excelPackage.Save();
}
return dataTemplate;
}
private static DataTable InitializeDataTable()
{
var dataTable = new DataTable();
dataTable.Columns.Add("Person Id", typeof(string));
dataTable.Columns.Add("Person Name", typeof(string));
return dataTable;
}
private static void PopulateData(IEnumerable<DataTemplateRow> data, DataTable dataTable)
{
foreach (var item in data)
{
var dataRow = dataTable.NewRow();
dataRow["Person Id"] = item.Id;
dataRow["Person Name"] = item.Name;
dataTable.Rows.Add(dataRow);
}
}
public IEnumerable<DataTemplateRow> GetTemplateData(long schoolId)
{
var personData = _schoolService.GetData(schoolId);
var result = personData.Data.Select(result => new DataTemplateRow
{
PersonId = result.Id,
PersonName = result.Name
});
return result;
}
public class DataTemplateRow
{
public long Id { get; set; }
public class Name { get; set; }
}
Since I am already loading the data from the data table I can't find a way to display the value as a hyperlink.
http://www.diamondschool/{personName} so depending the value in the cell, display the personame as hyperlink to that address

You need to format the Cell like this. Create a Hyperlink and set it with an Uri
ws.Cells[5, 5].Style.Font.UnderLine = true;
ws.Cells[5, 5].Style.Font.Bold = true;
ws.Cells[5, 5].Style.Font.Color.SetColor(Color.Blue);
ws.Cells[5, 5].Hyperlink = new Uri("https://www.google.nl");

Related

How to Check or Uncheck a Checkbox in Datagridview based on existing data record from Table

I need help on part of this code. I'm using a checkbox column in my DataGridView control. When I retrieve my data record, if a value exists then the checkbox should be checked, and if not it should remain unchecked. How to I accomplish that on a DataGridView with this kind of logic?
using (DataContext dtContext = new DataContext())
{
var query = (from i in dtContext.materialTBheader where i.proj == Proj_id select i);
foreach (var r in query)
{
if (!string.IsNullOrEmpty(r.materialheader_id.ToString()))
{
string[] row = { r.materialheader_id.ToString(), r.materialname, r.description, string.Format("{0:n2}", r.totalAmount), GetCount(r.materialname, txtMainProjectHeader_id, Convert.ToDecimal(r.totalAmount)), "", -- cell checkbox if record exist true checked if not false uncheck };
dGVMaterialHeaderList.Rows.Add(row);
}
}
}
It dosen't need to add your rows by foreach, use DataSource Property
Suppose you have a List of Person and you want to show in dataGridview, you have to option
1)add your column to data grid in visual studio properties window
2)add your column with coding
then map your data to grid
here is an simple example to help yo
public class Person
{
public int Id { get; set; }
public string LastName { get; set; }
public bool Married { get; set; }
}
private void Form1_Load(object sender, EventArgs e)
{
//your data from ef
var myData = new List<Person>
{
new Person{Id=1,LastName="A1",Married =true},
new Person{Id=1,LastName="A2",Married =false},
new Person{Id=1,LastName="A3",Married =true},
};
//your columns
var idColumn = new System.Windows.Forms.DataGridViewTextBoxColumn
{
Name = "Id",
HeaderText = "Id",
DataPropertyName = "Id"
};
var lastNameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn
{
Name = "LastName",
HeaderText = "LastName",
DataPropertyName = "LastName"
};
var marriedColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn
{
Name="Married",
HeaderText="Married",
DataPropertyName= "Married"
};
// add your columns to grid
dGVMaterialHeaderList.Columns.Add(idColumn);
dGVMaterialHeaderList.Columns.Add(lastNameColumn);
dGVMaterialHeaderList.Columns.Add(marriedColumn);
dGVMaterialHeaderList.AutoGenerateColumns = false;
//bind your data
dGVMaterialHeaderList.DataSource = myData;
}
In your case the answer is something like below:
using (DataContext dtContext = new DataContext())
{
var query = (from i in dtContext.materialTBheader where i.proj == Proj_id select i).ToList();
var gridData = query.Select(r=>new
{
materialheader_id = r.materialheader_id.ToString(),
r.materialname,
r.description,
totalAmount = string.Format("{0:n2}", r.totalAmount),
Count = GetCount(r.materialname, txtMainProjectHeader_id, Convert.ToDecimal(r.totalAmount)),
isExist = !string.IsNullOrEmpty(r.materialheader_id.ToString())?true:false
}).ToList();
dGVMaterialHeaderList.DataSource = gridData;
}
I don't know your data structure but I know this is not best approach you choose
I hope this can help you

Problem with filling a Table in c# from a list

I am working with WindowsForm and C# and I am filling out a List<> and everything is fine so far
In my list<> I have 103 records but when I pass to my DataTable no record appears only the headers, that is to say that when I receive my table everything shows in null
The truth is, I'm a little new to this and it's the first one that I'm working on.
List<MSProject.Task> tasks = new List<MSProject.Task>();
DataTable Tabla = new DataTable();
Tabla = ListToDataTable(tasks);
my code
public static DataTable ListToDataTable<T>(IList<T> data)
{
DataTable table = new DataTable();
//special handling for value types and string
if (typeof(T).IsValueType || typeof(T).Equals(typeof(string)))
{
DataColumn dc = new DataColumn("Value");
table.Columns.Add(dc);
foreach (T item in data)
{
DataRow dr = table.NewRow();
dr[0] = item;
table.Rows.Add(dr);
}
}
else
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
foreach (PropertyDescriptor prop in properties)
{
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
}
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
{
try
{
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
}
catch (Exception ex)
{
row[prop.Name] = DBNull.Value;
}
}
table.Rows.Add(row);
}
}
return table;
}
Thanks in advance
I've run your code and it's work, The problem I believe is that the MSProject.Task doesn't have any public properties and you are iterating only in properties. PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
see the code below:
//with properties
public class MSProject.Task
{
public string Name {get; set;}
public string code {get; set;}
}
//no properties
public class MSProject.Task2
{
public string Name;
public string code;
}
private void ShowRownsInGrid()
{
//it works shows rows in DataGridView!
List<MSProject.Task> tasks = new List<MSProject.Task>()
{
new MSProject.Task(){ Name = "Joao", code = "01215452124"},
new MSProject.Task(){ Name = "Maria", code = "4564678"},
};
DataTable Tabla = new DataTable();
Tabla = ListToDataTable(tasks);
MessageBox.Show(Tabla.Rows.Count.ToString()); //Show '2'
dataGridView1.DataSource = Tabla; //Show 2 rows
}
private void DontShowRownsInGrid()
{
//it doesn't work, no rows are displayed in the DataGridView!
List<MSProject.Task2> tasks = new List<MSProject.Task2>()
{
new MSProject.Task2(){ Name = "Joao", code = "01215452124"},
new MSProject.Task2(){ Name = "Maria", code = "4564678"},
};
DataTable Tabla = new DataTable();
Tabla = ListToDataTable(tasks);
MessageBox.Show(Tabla.Rows.Count.ToString()); //Show '2'
dataGridView1.DataSource = Tabla; //does not show lines
}

How can I write to a DataTable?

I'm in need of a fresh pair of eyes here. I'm trying to extract details from a user-uploaded file, add them to a DataTable, then write them to my SQL Server table.
It all appears to work nicely but for the actual fields being added to the DataTable (rather crucial!). The code runs to completion but with a blank DataTable, so obviously nothing is being written to my table. I attach my Controller - I'm sure it's something obvious that I'm missing, but I can't determine why.
public class FileUploaderController : Controller
{
public FileUploaderController()
{
db = new DatabaseContext();
}
public FileUploaderController(DatabaseContext context)
{
db = context;
}
private DatabaseContext db { get; }
public ActionResult UploadFilesPartial()
{
return View();
}
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
var dt = CreateDataTable();
if (file != null)
{
var fileName = file.FileName;
var filePath = Path.GetFullPath(fileName);
var fileType = Path.GetExtension(fileName);
DataRow fileDetails = dt.NewRow();
fileDetails["FileName"] = fileName;
fileDetails["FilePath"] = filePath;
fileDetails["FileType"] = fileType;
UploadToDataBase(db, dt);
}
return RedirectToAction("NettingBatch", "Views");
}
private DataTable CreateDataTable()
{
System.Data.DataTable table = new DataTable("FileUploads");
DataColumn id;
id = new DataColumn
{
DataType = System.Type.GetType("System.Int32"),
ColumnName = "Id",
ReadOnly = true,
Unique = true
};
table.Columns.Add(id);
DataColumn name;
name = new DataColumn
{
DataType = System.Type.GetType("System.String"),
ColumnName = "FileName",
AutoIncrement = false,
Caption = "FileName",
ReadOnly = false,
Unique = false
};
table.Columns.Add(name);
DataColumn path;
path = new DataColumn
{
DataType = System.Type.GetType("System.String"),
ColumnName = "FilePath",
AutoIncrement = false,
Caption = "FilePath",
ReadOnly = false,
Unique = false
};
table.Columns.Add(path);
DataColumn type;
type = new DataColumn
{
DataType = System.Type.GetType("System.String"),
ColumnName = "FileType",
AutoIncrement = false,
Caption = "FileType",
ReadOnly = false,
Unique = false
};
table.Columns.Add(type);
DataColumn[] PrimaryKeyColumns = new DataColumn[1];
PrimaryKeyColumns[0] = table.Columns["Id"];
table.PrimaryKey = PrimaryKeyColumns;
return table;
}
private void UploadToDataBase(DbContext context, DataTable data)
{
try
{
var columnMappings = new List<Tuple<string, string>>
{
new Tuple<string, string>("Id", "Id"),
new Tuple<string, string>("FileName", "FileName"),
new Tuple<string, string>("FilePath", "FilePath"),
new Tuple<string, string>("FileType", "FileType"),
};
PopulateHistoryTable.BulkCopyDataTableIntoDatabase(context, data, "[mdp].[FileUploads]",
columnMappings);
}
catch (Exception e)
{
Console.WriteLine(e.InnerException);
}
}
}
I expect the details of my test file that I upload on my view to be extracted and written back to FileUploads table. Actual results are blank.
NewRow returns a row that matches your DataTable scheme, but it doesn't actually "add" it to the DataTable. Use the "Add" function of the Rows collection to do that:
DataRow fileDetails = dt.NewRow();
fileDetails["FileName"] = fileName;
fileDetails["FilePath"] = filePath;
fileDetails["FileType"] = fileType;
dt.Rows.Add(fileDetails);

Difficulties with C# + Excel

I have a problem.
I have an Excel File where sometimes the same customer is in 2 rows.
But not always.
Its like:
Click
Now, i want to create a DataGrid in C# which can list this in one row like:
Click
I know it would be easier to change the Excel file, but assume it wouldnt work that way(we get the file like this and we cant change it)
I know i could too just make another Excel File and make it with Excel(already did it this way, but we would need it more as C#)
Now i am at this point:
private void button2_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog() { Filter = "Excel Arbeitsmappe |*.xlsx", ValidateNames = true };
if (ofd.ShowDialog() == DialogResult.OK)
textBox1.Text = ofd.SafeFileName;
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = false;
string filename = ofd.FileName;
Excel.Workbook workbook = excelApp.Workbooks.Open(filename);
Excel.Worksheet worksheet = workbook.Worksheets[1];
dataGridView1.ColumnCount = 2;
dataGridView1.Columns[0].Name = "Number";
dataGridView1.Columns[1].Name = "Street";
int rows = worksheet.UsedRange.Rows.Count;
for (int i = 2; i <= rows; i++)
{
string combinehr = worksheet.Cells[i, 150].Text + worksheet.Cells[i, 151].Text;
dataGridView1.Rows.Add(worksheet.Cells[i,29].Text, combinehr);
}
}
How do i expand it that it works like i want?
I would be so grateful
(sorry for the english)
With a reference to ExcelDataReader, ExcelDataReader.DataSet and DataSetExtensions (.Net) you can read the Excel file pretty easy into a DataSet, then you just have to work with the logic:
Input file:
using System;
using System.Data;
using System.IO;
using System.Linq;
using ExcelDataReader;
public DataTable GetTableFromExcel(string filePath)
{
DataSet ds = new DataSet();
using (var stream = System.IO.File.Open(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
ds = reader.AsDataSet();
}
}
DataTable table = new DataTable();
table.Columns.Add(new DataColumn("CustomerNr"));
table.Columns.Add(new DataColumn("Address"));
// Set column names
for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
{
// DataColumn.ColumnName can't be empty when DataColumn is part
// of a DataTable (throws ArgumentException)
string columnName = ds.Tables[0].Rows[0][i].ToString();
if (string.IsNullOrWhiteSpace(columnName))
{
columnName = $"Column{i}";
}
ds.Tables[0].Columns[i].ColumnName = columnName;
}
// Remove the first row containing the headers
ds.Tables[0].Rows.Remove(ds.Tables[0].Rows[0]);
// I don't have the benchmarks with me right now, but I've tested
// DataTable.Select vs DataTable.AsEnumerable.Select many times
// and the AsEnumerable method its faster, that's why you need the
// reference to System.Data.DataSetExtensions
var enumerableTable = ds.Tables[0].AsEnumerable();
// list of unique products
var products = enumerableTable.Select(row => row.Field<string>("Product")).Distinct();
// Add a column for each product
foreach (string product in products)
{
table.Columns.Add(new DataColumn(product));
}
// list of unique customers
var customerNumbers = enumerableTable.Select(row => row.Field<double>("CustomerNr")).Distinct();
foreach (var customerNumber in customerNumbers)
{
DataRow record = table.NewRow();
record["CustomerNr"] = customerNumber;
record["Address"] = enumerableTable.First(row => row.Field<double>("CustomerNr").Equals(customerNumber))[1];
for (int i = 2; i < table.Columns.Count; i++)
{
DataRow product = enumerableTable.FirstOrDefault(row => row.Field<double>("CustomerNr").Equals(customerNumber)
&& row.Field<string>("Product").Equals(table.Columns[i].ColumnName));
// Quantity = 0 if product is null
record[i] = product?["Quantity"] ?? 0;
}
table.Rows.Add(record);
}
return table;
}
Result DataTable:
The same result as #IvanGarcíaTopete via Microsoft.Office.Interop.Excel.
Class ExcelModel for Excel data:
public class ExcelModel
{
public string CustomerNr { get; set; }
public string Address { get; set; }
public string Product { get; set; }
public string Quantity { get; set; }
}
Read Excel and fill out model:
private void OpenReadExcel()
{
var dlg = new OpenFileDialog();
if (dlg.ShowDialog() != DialogResult.OK) return;
var exApp = new Microsoft.Office.Interop.Excel.Application();
Workbook exWbk = exApp.Workbooks.Open(dlg.FileName);
Worksheet wSh = exWbk.Sheets[1];
int k = 2;
Customers.Clear();
while (wSh.Cells[k, 1].Text != "" && wSh.Cells[k, 1].Value != null)
{
var rowExcelModel = new ExcelModel()
{
CustomerNr = wSh.Cells[k, 1].Text,
Address = wSh.Cells[k, 2].Text,
Product = wSh.Cells[k, 3].Text,
Quantity = wSh.Cells[k, 4].Text
};
Customers.Add(rowExcelModel);
k++;
}
exApp.Quit();
}
Generate Data table:
private void GenerateDataTable()
{
// unique products and customers
var products = Customers.Select(x => x.Product).Distinct().ToList();
var customers = Customers.Select(x => x.CustomerNr).Distinct().ToList();
// columns CustomerNr and Address
var dataTable = new System.Data.DataTable();
dataTable.Columns.Add(new DataColumn("CustomerNr"));
dataTable.Columns.Add(new DataColumn("Address"));
// columns for each product
foreach (var product in products)
{
dataTable.Columns.Add(new DataColumn(product));
}
//fill rows for each customers
foreach (var customer in customers)
{
var row = dataTable.NewRow();
row["CustomerNr"] = customer;
row["Address"] = Customers.Where(x => x.CustomerNr == customer).Select(x => x.Address).FirstOrDefault();
foreach (var product in products)
{
var quantity = Customers.Where(x => x.CustomerNr == customer && x.Product == product)
.Select(x => x.Quantity).FirstOrDefault();
row[product] = quantity ?? "0";
}
dataTable.Rows.Add(row);
}
dataGridView1.DataSource = dataTable;
}

DataGridView generating rows without data

I've searched all over here and Google and still can't find an answer to this. I'm playing around with Amazon's API and am making a simple Windows Form to try and display the data in a DataGridView. The GridView is generating 10 rows for the 10 results I am getting, but is not filling the rows with the actual data. They're just blank.
The code below is a method (GetResults) that return a DataTable. I didn't show all of it because there is a bunch of code above to get the data.
DataTable dt = new DataTable();
dt.Columns.Add("ASIN", typeof(string));
dt.Columns.Add("Title", typeof(string));
// write out the results
foreach (var item in response.Items[0].Item)
{
Product product = new Product(item.ASIN, item.ItemAttributes.Title);
Console.WriteLine(product.ASIN);
var dr = dt.NewRow();
dr["ASIN"] = product.ASIN;
dr["Title"] = product.Title;
dt.Rows.Add();
}
return dt;
}
private void btnSearch_Click(object sender, EventArgs e)
{
dgvProducts.AutoGenerateColumns = false;
dgvProducts.DataSource = GetReults();
}
I know it is getting the info because I am writing it to console and it is showing up correctly.
I also have this basic class for the Product:
public class Product
{
private string asin;
private string title;
public Product() { }
public Product(string newAsin, string newTitle)
{
this.asin = newAsin;
this.title = newTitle;
}
public string ASIN
{
get { return asin; }
set { asin = value; }
}
public string Title
{
get { return title; }
set { title = value; }
}
I've tried setting AutoGenerateColumns = false and setting the column data bindings myself, but that didn't do anything either.
You're adding an empty row to the table, not adding your newly created row.
Change
dt.Rows.Add();
To
dt.Rows.Add(dr);

Categories

Resources