I need update custom Excel ribbon of working file without closing file from another Excel file.
I try make this task using Open XML SDK for Office.
Here class that export and import custom ribbon.
public static class OpenDocumentTools
{
public static bool ExportCustomRibbon(string fileName, string exportDir)
{
try
{
//Get RibbonExtensibilityPart
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(fileName, true);
RibbonExtensibilityPart ribbon = spreadsheetDocument.RibbonExtensibilityPart;
//Clear directory
foreach (string fil in Directory.EnumerateFiles(exportDir).ToList())
File.Delete(fil);
//Processing images
foreach (ImagePart imagePart in ribbon.ImageParts.ToList())
{
Image img = Image.FromStream(imagePart.GetStream());
string[] arrPath = imagePart.Uri.OriginalString.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
string imageName = arrPath[arrPath.Length - 1];
img.Save(string.Format("{0}\\{1}", exportDir, imageName));
}
//Save ribbon xml
StreamWriter sw = File.CreateText(string.Format("{0}\\Ribbon.xml", exportDir));
sw.WriteLine(ribbon.CustomUI.OuterXml);
sw.Close();
return true;
}
catch(Exception ex)
{
return false;
}
}
public static bool ImportCustomRibbon(string fileName, string xmlFile, string importDir)
{
try
{
//Read xml content
string content = File.OpenText(xmlFile).ReadToEnd();
using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
{
//Get or create RibbonExtensibilityPart
RibbonExtensibilityPart ribbon = document.RibbonExtensibilityPart;
if (ribbon == null)
ribbon = document.AddRibbonExtensibilityPart();
//Load xml content to ribbon
ribbon.CustomUI = new CustomUI(content);
ribbon.CustomUI.Save();
//Remove image parts
foreach (ImagePart imagePart in ribbon.ImageParts.ToList())
ribbon.DeletePart(imagePart);
//Load images to ribbon
foreach (string fileNam in Directory.EnumerateFiles(importDir).ToList())
{
ImagePart imagePart = null;
switch (Path.GetExtension(fileNam))
{
case ".png":
imagePart = ribbon.AddImagePart(ImagePartType.Png, Path.GetFileNameWithoutExtension(fileNam));
break;
case ".jpeg":
imagePart = ribbon.AddImagePart(ImagePartType.Jpeg, Path.GetFileNameWithoutExtension(fileNam));
break;
default:
continue;
}
if (imagePart != null)
{
using (FileStream stream = new FileStream(fileNam, FileMode.Open))
{
stream.Position = 0;
imagePart.FeedData(stream);
}
ribbon.AddPart(imagePart, Path.GetFileNameWithoutExtension(fileNam));
}
}
}
return true;
}
catch(Exception ex)
{
return false;
}
}
}
Here calling code:
static void Main(string[] args)
{
bool res = OpenDocumentTools.ExportCustomRibbon(#"D:\15\Ribbon\Source.xlsm", #"D:\15\Ribbon\Export");
res = OpenDocumentTools.ImportCustomRibbon(#"D:\15\Ribbon\Dest.xlsm", #"D:\15\Ribbon\Export\Ribbon.xml", #"D:\15\Ribbon\Export");
}
When Excel-files are closed, code working fine. But if Excel-file is open, I have exception:
"The process cannot access the file 'D:\15\Ribbon\Dest.xlsm' because it is being used by another process.” This is occurred, when programm trying execute “using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))”.
Does anybody know what way I can use for updating ribbon without closing file?
Related
I know there are a lot of similar topics on this website, but I think that I went through most of them and still cannot debug this piece of code. I really need to get this working. I'm newbie to C# and programming. Tho, I did this same assignment in Java, but for some reason, I can't make it work here. If some could please pitch in...
So I have some objects, which I am keeping in .txt file, one line = data for one object. First data of the line is an Id of an object, primary key basically. Right now I am implementing CRUD operations, that is, an Update. This edit function is supposed to contribute to that functionality.
If a user edit some of the selected object properties, that change needs to be reflected in .txt file. So, I will go through every object/line in the file, write them to some temp.txt file, once I hit object which has same Id as the passed object o, that means I need to write that edited object to temp.txt. After that I need to rename temp.txt to original file and delete temp.txt.
I have tried bunch of options and combinations, but none worked.
I really make sure that GetTxtPath returns correct absolute path from within my project.
Version 1:
public static void edit(Transformable o, string fileName)
{
try
{
if (!File.Exists(FileUtils.GetTxtPath("temp.txt")))
{
File.Create(FileUtils.GetTxtPath("temp.txt"));
}
using (FileStream stream = File.OpenRead(FileUtils.GetTxtPath(fileName)))
using (FileStream writeStream = File.OpenWrite(FileUtils.GetTxtPath("temp.txt")))
{
StreamReader reader = new StreamReader(stream);
StreamWriter writer = new StreamWriter(writeStream);
String line;
while ((line = reader.ReadLine()) != null)
{
if (!line.Equals(""))
{
if (o.GetId() == getIdFromString(line))
{
writer.Write(o.WriteToFile());
}
else
{
writer.Write(line + "\n");
}
}
else
{
continue;
}
}
}
}
catch (FileNotFoundException e)
{
Console.WriteLine($"The file was not found: '{e}'");
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine($"The directory was not found: '{e}'");
}
catch (IOException e)
{
Console.WriteLine($"The file could not be opened: '{e}'");
}
}
public static string GetTxtPath(string fileName)
{
var startDirectory =
Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;
var absPath = startDirectory + #"\data\" + fileName;
return absPath;
}
private static int getIdFromString(string line)
{
return Int32.Parse(line.Split('|')[0]);
}
Version 2:
public static void Edit(Transformable o, string fileName)
{
try
{
if (!File.Exists(FileUtils.GetTxtPath("temp.txt")))
{
File.Create(FileUtils.GetTxtPath("temp.txt"));
}
using (StreamReader reader = FileUtils.GetTxtReader(fileName))
using (StreamWriter writer = FileUtils.GetTxtWriter("temp.txt"))
{
String line;
while ((line = reader.ReadLine()) != null)
{
if (!line.Equals(""))
{
if (o.GetId() == getIdFromString(line))
{
writer.Write(o.WriteToFile());
}
else
{
writer.Write(line + "\n");
}
}
else
{
continue;
}
}
}
File.Move(FileUtils.GetTxtPath("temp.txt"), FileUtils.GetTxtPath(fileName));
File.Delete(FileUtils.GetTxtPath("temp.txt"));
//Here I tied many differenet options but nonthing worked
//Here is Java code which did the job of renaming and deleting
//------------------------------------------------------------
// File original = FileUtils.getFileForName(fileName);
// File backUpFile = new File("backUp");
// Files.move(original.toPath(), backUpFile.toPath(),
// StandardCopyOption.REPLACE_EXISTING);
// File temporary = FileUtils.getFileForName(temporaryFilePath);
// temporary.renameTo(original);
// backUpFile.delete();
// File original = FileUtils.getFileForName(path);
//--------------------------------------------------------
//public static File getFileForName(String name)
//{
// String dir = System.getProperty("user.dir");
// String sP = System.getProperty("file.separator");
// File dirData = new File(dir + sP + "src" + sP + "data");
// File file = new File(dirData.getAbsolutePath() + sP + name);
// return file;
//}
//---------------------------------------------------------------------
}
catch (FileNotFoundException e)
{
Console.WriteLine($"The file was not found: '{e}'");
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine($"The directory was not found: '{e}'");
}
catch (IOException e)
{
Console.WriteLine($"The file could not be opened: '{e}'");
}
public static StreamReader GetTxtReader(string fileName)
{
var fileStream = new FileStream(GetTxtPath(fileName), FileMode.Open, FileAccess.Read);
return new StreamReader(fileStream, Encoding.UTF8);
}
public static StreamWriter GetTxtWriter(string fileName)
{
FileStream fileStream = new FileStream(GetTxtPath(fileName), FileMode.Append);
return new StreamWriter(fileStream, Encoding.UTF8);
}
public static void Edit(Transformable o, string fileName)
{
try
{
string tempName = "temp.txt"; // create here correct path
using (var readStream = File.OpenRead(fileName))
using (var writeStream = File.OpenWrite(tempName))
using (var reader = new StreamReader(readStream))
using (var writer = new StreamWriter(writeStream))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (!line.Equals(""))
{
if (o.GetId() == GetId(line))
{
writer.WriteLine(o.ToWriteableString());
}
else
{
writer.WriteLine(line);
}
}
}
}
File.Delete(fileName);
File.Move(tempName, fileName);
}
catch ...
}
File.OpenWrite method opens an existing or creates a new file for writing. So there is no need to manually check and create the file.
You have wrapped FileStreams in a using statement quite correctly. However, StreamReader and StreamWriter also must to be released after use.
I renamed some methods, giving them names that conform to the naming rules in C#: Edit, GetId, ToWriteableString.
The else branch with the continue statement is not needed.
In the end, just use the File.Delete and File.Move methods.
Note: the int.Parse method can throw exceptions that also need to be handled.
I want to search string in excel file, I used to use Microsoft.Office.Interop.Excel in my program and It works perfectly. I use this code below:
findRange1 = range1.Find("apple", LookAt: Excel.XlLookAt.xlWhole);
However, I faced a problem using interop excel in the server side. And I change my program using OpenXML. I want to do the searching method as well using OpenXML. how to do it in OpenXML?
1) Import your excel document .xlsx or xls to SpreadsheetDocument of OpenXMl.
public WorkbookPart ImportExcel()
{
try
{
string path = #"your path to excel document";
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
MemoryStream m_ms = new MemoryStream();
fs.CopyTo(m_ms);
SpreadsheetDocument m_Doc = SpreadsheetDocument.Open(m_ms, false);
return m_Doc.WorkbookPart;
}
}
catch (Exception ex)
{
System.Diagnostics.Trace.TraceError(ex.Message + ex.StackTrace);
}
return null;
}
2) Create method to get index in the form of [row, column] by using specific search criteria.
public string GetIndexBySearch(string search)
{
WorkbookPart workbookPart = ImportExcel();
var sheets = workbookPart.Workbook.Descendants<Sheet>();
Sheet sheet = sheets.Where(x => x.Name.Value == "you sheet name in excel document").FirstOrDefault();
string index = string.Empty;
if (sheet != null)
{
var worksheetPart = (WorksheetPart)workbookPart.GetPartById(sheet.Id);
var rows = worksheetPart.Worksheet.Descendants<Row>().ToList();
// Remove the header row
rows.RemoveAt(0);
foreach (var row in rows)
{
var cellss = row.Elements<Cell>().ToList();
foreach (var cell in cellss)
{
var value = cell.InnerText;
var stringTable = workbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
bool isFound = value.Trim().ToLower().Contains(search.Trim().ToLower());
if (isFound)
{
index = $"[{row.RowIndex}, {GetColumnIndex(cell.CellReference)}]";
return index;
}
}
}
}
return index;
}
3) Finally this method gives you column index by passing column name.
private static int? GetColumnIndex(string cellReference)
{
if (string.IsNullOrEmpty(cellReference))
{
return null;
}
string columnReference = Regex.Replace(cellReference.ToUpper(), #"[\d]", string.Empty);
int columnNumber = -1;
int mulitplier = 1;
foreach (char c in columnReference.ToCharArray().Reverse())
{
columnNumber += mulitplier * ((int)c - 64);
mulitplier = mulitplier * 26;
}
return columnNumber + 1;
}
4) Considering all above 3 methods are in same class called MyClass. Then you will use GetIndexBySearch like
MyClass c = new MyClass();
string index = c.GetIndexBySearch("AFL");
Output:
How do i convert a jpg/png/txt or any file format to pdf using mvc c#.
Here is the code:
public ActionResult SaveProfileDocument(string code)
{
bool isSavedSuccessfully = true;
string fName = "";
string _documentname = String.Empty;
try
{
foreach (string fileName in Request.Files)
{
HttpPostedFileBase file = Request.Files[fileName];
//Save file content goes here
fName = file.FileName;
if (file != null && file.ContentLength > 0)
{
var originalDirectory = new DirectoryInfo(string.Format("{0}Documents\\Profile\\" + code, Server.MapPath(#"\")));
string pathString = System.IO.Path.Combine(originalDirectory.ToString());
var fileName1 = Path.GetFileName(file.FileName);
bool isExists = System.IO.Directory.Exists(pathString);
if (!isExists)
System.IO.Directory.CreateDirectory(pathString);
_documentname=fName;
var path = string.Format("{0}\\{1}", pathString, file.FileName);
if (System.IO.File.Exists(path)) {
_documentname=Guid.NewGuid()+"_"+file.FileName;
var path2 = string.Format("{0}\\{1}", pathString,_documentname );
file.SaveAs(path2);
}
else {
file.SaveAs(path);
}
}
}
}
catch (Exception ex)
{
isSavedSuccessfully = false;
}
if (isSavedSuccessfully)
{
return Json(new { Message = fName, documentname = _documentname });
}
else
{
return Json(new { Message = "Error in saving file", documentname=""});
}
}
In the above code i am saving the file.but
here i need to convert the file and then save.
so for convert i need a separate class or method here only call that method.
The thing is that while upload a file inthat time need to convert pdf any file to convert pdf. and save in folder or whatever.
can't convert an image file to PDF. You can create a PDF file and add the image file to it:
string pdfpath = Server.MapPath("PDFs");
string imagepath = Server.MapPath("Images");
Document doc = new Document();
try
{
PdfWriter.GetInstance(doc, new FileStream(pdfpath + "/Images.pdf", FileMode.Create));
doc.Open();
doc.Add(new Paragraph("GIF"));
Image gif = Image.GetInstance(imagepath + "/mikesdotnetting.gif");
doc.Add(gif);
}
catch (Exception ex)
{
//Log error;
}
finally
{
doc.Close();
}
here i am refer:
https://www.mikesdotnetting.com/article/87/itextsharp-working-with-images
How do I get the Path or the file name of workbook in the below code so that I can get the work book that is edited. I have used ExpertXLS – Excel Spreadsheet Library for .NET - C#/VB.NET here
using ExpertXls;
namespace IQC
{
public class CSFB
{
public static string GenerateTemplateForCurrentGridView(IQO[] items, string colname, int icol)
{
/*Some Code here*/
string pathSource = HttpContext.Current.Server.MapPath("~/pdf/ExportTemplate.xlsx");
ExpertXls.ExcelLib.ExcelWorkbook workbook = new ExpertXls.ExcelLib.ExcelWorkbook(#pathSource);
workbook.LicenseKey = Inq.Configuration.Settings.Value("ExpertPdfLicenseKey");
ExpertXls.ExcelLib.ExcelWorksheet ws = workbook.Worksheets["ImportTemplate"];
ExpertXls.ExcelLib.ExcelCellStyle Style1 = workbook.Styles.AddStyle("Style1");
Style1.Fill.FillType = ExpertXls.ExcelLib.ExcelCellFillType.SolidFill;
Style1.Fill.SolidFillOptions.BackColor = Color.Yellow;
foreach (string cols in colname.Split(','))
{
ws[cols].Style = Style1;
}
/*Some Code here*/
}
}
}
You may use Application.ActiveWorkbook.FullName if the workbook is active workbook. Also you can try using workbook.Path. Refer the link.
Adding below code worked. I have saved the worked book in "pathsource"
System.IO.FileStream fs = new FileStream(pathSource, FileMode.OpenOrCreate, FileAccess.ReadWrite);
string fileName = fs.Name;
try
{
workbook.Save(fs);
}
catch (Exception ex)
{
Logger.Error(" Error:", ex);
}
finally
{
workbook.Close();
}
Requirment: To generate invoice in pdf format on company template and send it in email.
Approach I used:
Placed the company template at path: ~Content/InvoiceTemplate/
Using iTextsharp Pdf stamper, generated pdf, saved it at path: ~/Content/reports/
In email module, picked the file generated above and attached to email to be sent
Problem: Every invoice generated is being stored on application server, making application heavier day by day.
Question: What is the other way out to send the generated in voice in email, without saving it on application server?
Code:
public static void WriteInTemplate(List<Models.Statement> statementList)
{
try
{
string invoiceNumber = statementList.FirstOrDefault().Invoice.ToString().Trim();
using (Document document = new Document())
{
FileStream fileStream = new FileStream(HostingEnvironment.MapPath("~/Content/reports/" + invoiceNumber + ".pdf"), FileMode.Create);
using (PdfSmartCopy smartCopy = new PdfSmartCopy(document, fileStream))
{
document.Open();
int statementCounter = 0;
int numberOfItems = statementList.Count();
int remainingItems = numberOfItems;
int maxItemsPerPage = 17;
if (remainingItems > 0)
{
do
{
if (remainingItems < maxItemsPerPage)
maxItemsPerPage = remainingItems;
PdfReader pdfReader = new PdfReader(HostingEnvironment.MapPath("~/Content/InvoiceTemplate/invoiceTemplate.pdf"));
using (var memoryStream = new MemoryStream())
{
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, memoryStream))
{
string month = null;
string day = null;
string year = null;
AcroFields pdfFields = pdfStamper.AcroFields;
{//billing address
pdfFields.SetField("BillToCompany", statementList.FirstOrDefault().BillToCompany.ToString().Trim().ToUpper());
pdfFields.SetField("BillToContact", statementList.FirstOrDefault().BillToContact.ToString().Trim().ToUpper());
}
//---------------------snip------------------------------//
//---------------------snip------------------------------//
}
{//invoice sum up
double subTotal = Convert.ToDouble(statementList.FirstOrDefault().Subtotal);
pdfFields.SetField("Subtotal", statementList.FirstOrDefault().Subtotal.ToString("0.00").Trim());
double misc = Convert.ToDouble(statementList.FirstOrDefault().Misc);
pdfFields.SetField("Misc", statementList.FirstOrDefault().Misc.ToString("0.00").Trim());
double tax = Convert.ToDouble(statementList.FirstOrDefault().Tax);
pdfFields.SetField("Tax", statementList.FirstOrDefault().Tax.ToString("0.00").Trim());
}
pdfStamper.FormFlattening = true; // generate a flat PDF
}
pdfReader = new PdfReader(memoryStream.ToArray());
smartCopy.AddPage(smartCopy.GetImportedPage(pdfReader, 1));
}
remainingItems = remainingItems - maxItemsPerPage;
} while (remainingItems > 0);
}
}
}
emailController.CreateMessageWithAttachment(invoiceNumber);
}
catch (Exception e)
{
}
}
You can try to attach the file from a memory stream. You can search Google for "C# Attach file from memory stream".
Here is a sample snippet:
mail.Attachments.Add(new Attachment(memoryStream, "example.txt", "text/plain"));
Or:
email attachment from the MemoryStream comes empty
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/049420de-7e93-4fcb-9920-0c1cdf4ca420/
http://www.codeproject.com/KB/IP/InMemoryMailAttachment.aspx
If the pdf files aren't too large, and you're not using a server farm, and you don't have millions of people generating invoices at the same time..
Then you could always use a MemoryStream and pass the memory stream to your email service.
Instead of creating a file in your application directory you should try creating files in temp folder.. and when you are done with the file you should delete them.. this way files won't take so much space on your drive..
this is a tempfile class that i have used with iTextSharp to export pdf after filling the form.
sealed class TempFile : IDisposable
{
string path;
public TempFile() : this(System.IO.Path.GetTempFileName()) { }
public TempFile(string path)
{
if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path");
this.path = path;
}
public string Path
{
get
{
if (path == null) throw new ObjectDisposedException(GetType().Name);
return path;
}
}
~TempFile() { Dispose(false); }
public void Dispose() { Dispose(true); }
private void Dispose(bool disposing)
{
if (disposing)
{
GC.SuppressFinalize(this);
}
if (path != null)
{
try { File.Delete(path); }
catch { } // best effort
path = null;
}
}
}
you should try
using(TempFile file = new TempFile())
{
.....= new FileStream(file.Path,.....)
//pdf form filling using iTextSharp
var arry = GetBytesArray(file.Path);
//Send Array to response and set content type to pdf..
}