NPOI: Create a cell containing two differently sized strings - c#

so as the title intends, I want to creaete a cell in a NPOI 2.1.3-Workbook containing 2 strings: A "normal"-sized string and a "small"-sized string. => I want to change the font-size for a part of the cell.
My code so far:
var planCell = planRow.CreateCell(lineCnt + 1);
var planCellStyle = workbook.CreateCellStyle();
planCellStyle.WrapText = true;
planCellStyle.VerticalAlignment = VerticalAlignment.Top;
planCellStyle.Alignment = HorizontalAlignment.Left;
var font = workbook.CreateFont();
font.FontName = HSSFFont.FONT_ARIAL;
font.FontHeightInPoints = 16;
font.Boldweight = (short)FontBoldWeight.Bold;
planCellStyle.SetFont(font);
planCell.CellStyle = planCellStyle;
string planTitleContent = string.Empty;
... (some logic to get desired string for planTitleContent)
string planInfoContent = string.Empty;
... (some logic to get desired string for planInfoContent)
planCell.SetCellValue(planTitleContent + "\n\n"+planInfoContent);
To be precise, I want the "planInfoContent"-part to be shown in a smaller font-size than the "planCellContent"-part. I searched a lot, but I just found the CellStyle-value which applies to the whole cell. So I hope I am missing something for two cells are not really an option.

Just figured it out myself :)
First, create 2 fonts of the desired format (for me and for simplicities sake, only the font size is of relevance):
var font1 = excel.CreateFont();
font1.FontName = HSSFFont.FONT_ARIAL;
font1.FontHeightInPoints = 12;
font1.Boldweight = (short)FontBoldWeight.Normal;
var font2 = excel.CreateFont();
font2.FontName = HSSFFont.FONT_ARIAL;
font2.FontHeightInPoints = 8;
font2.Boldweight = (short)FontBoldWeight.Normal;
Then, after you got your string(s), make use of (N)POIs applyFont-Method.
One of its implementations in NPOI has the following signature:
applyFont(int startIndex, int endIndex, IFont font)
so now, having string planTitleContent and string planInfoContent, the remaining steps are pretty obvious: Just create an Instance of IRichTextString and add your strings to it via constructor-parameter. Then, apply the wanted fonts via the index like so:
IRichTextString formattedCellContent = new HSSFRichTextString(planTitleContent + "\n"+planInfoContent);
richString.ApplyFont(0, planTitleContent.Length, font1);
richString.ApplyFont(planTitleContent.Length + 1, (planTitleContent + "\n" + planInfoContent).Length, font2);
planCell.SetCellValue(formattedCellContent);
so, this works like a charm for me. Hope it helps some other folks out!

Related

use the conditional format with epplus

I´m trying to aplly a conditional format to a an Excel using eppplus, in that case i want to apply a pattern to all odd rows. so i try use the mod function, but not working, i don´t know how to put the formula
ExcelAddress _formatRangeAddress = new ExcelAddress("A2:Q" + (listSize+ 1));
string _statement = "MOD(ROW();2)=0";
var _cond1 = hoja.ConditionalFormatting.AddExpression(_formatRangeAddress);
_cond1.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
_cond1.Style.Fill.BackgroundColor.Color = System.Drawing.Color.Gray;
_cond1.Formula = _statement;
Check the formula string. I think you want a , instead of that ;. So change this:
string _statement = "MOD(ROW();2)=0";
to this:
string _statement = "MOD(ROW(),2)=0";

Conditional formatting to entire row

I have a code in C# with EPPLUS for Excel that fills a cell green if the value of the cell is over 100. It works:
ExcelAddress _formatRangeAddress = new ExcelAddress("G4:G" + (c.Count + 4));
string _statement = "IF(G4>100,1,0)";
var _cond2 = hoja.ConditionalFormatting.AddExpression(_formatRangeAddress);
_cond2.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
_cond2.Style.Fill.BackgroundColor.Color = System.Drawing.Color.LimeGreen;
_cond2.Formula = _statement;
But what I really need is to fill the entire row. If I change the range:
ExcelAddress _formatRangeAddress = new ExcelAddress("A4:G" + (c.Count + 4));
Applies only for the cells in the A column, not to the entire row.
What I am doing wrong?
Make the reference to G4 absolute otherwise the formula will be apply relative to that cell. So change this line:
string _statement = "IF(G4>100,1,0)";
to apply to the entire row based ONLY on G4
string _statement = "IF($G$4>100,1,0)";
(Response to Comments)
to apply to entire rows relative to row number but keep the column fixed to G:
string _statement = "IF($G4>100,1,0)";

Segoe UI Symbols - Programmatically

EDIT:
Below is the format of my XML. It contains data for my IconSheet. I just put only one icon Hex Value for sample.
<Item>
<ItemInfo>
<Value>uE101</Value>
<Name>1</Name>
</ItemInfo>
</Item>
Here is a snippet from my Code
private void OnLoaded(object sender, RoutedEventArgs e)
{
data = (from query in XElement.Load("Data.xml").Descendants("ItemInfo")
select new ItemInfo
{
value = (int)(query.Element("Value").Value),
name = (string)query.Element("Name")
}).ToList();
int itemcount = data.length;
while (itemcount-- > 0)
{
TextBlock t = new TextBlock()
{
Width = 75,
Height = 75,
Text = #"\" + data[itemcount].value,
FontFamily = new FontFamily("Segoe UI Symbol")
};
wrapPanel.Children.Add(t);
}
}
in the Snippet Above data[itemcount].value contains data as "uE101". This does not work.
Below code works.
Text = "\uE101"
Any Help would be greatly appreciated.
UPDATE:
With Help from har07 and mishan comments i now have a clear cut idea as to how to handle HEX codes in C#. Thanks for the help. But i Updated the Question what I am trying with and this is what is causing the problem for me.
You can't separate backslash from next characters in this case. This code :
#"\" + "uE101"
is equal to this :
"\\uE101"
which will output this string instead of special character :
\uE101
They need to be written as single string expression :
"\uE101"
UPDATE :
You can either go with #mishan's second solution by storing only hexadecimal part of the character in xml (<Value>E101</Value>), then parse it to int -> convert int to char -> convert char back to string (following is the example to clarify what I mean) :
.....
TextBlock t = new TextBlock()
{
Width = 75,
Height = 75,
Text = ((char)int.Parse(data[itemcount].value, NumberStyles.HexNumber)).ToString(),
FontFamily = new FontFamily("Segoe UI Symbol")
};
.....
Or to write the exact character to xml and specify xml encoding to a format that support your special characters. You didn't show the codes to create that xml, so I can't help with exact sample that close to yours. But you can search for this topic by keyword "c# write xml document with specific encoding" and will find many examples.
Well, har07 answered your problem in his reply, so I'll just add some possible solutions that come to mind.
1.STORE THE WHOLE CHARACTERS
add the backslash to the data - then it will work
When creating the data, add the backslash to it immediately so it's already complete
2. STORE CHARACTERS AS (HEXADECIMAL) NUMBERS
or store them as characters right away, that would be the best option
when you need to assemble them for some reason, you just do conversion from numbers to characters and voila....
EXAMPLE:
while (itemcount-- > 0)
{
//can be achieved if data[].value is integer
//for testing purposes
//I used integer with value 0xE101
//int a = 0xe101;
TextBlock t = new TextBlock()
{
Width = 75,
Height = 75,
Text = ((char)data[itemcount].value).ToString(),
//Text = ((char)a).Tostring(),
FontFamily = new FontFamily("Segoe UI Symbol")
};
wrapPanel.Children.Add(t);
}
THE UPDATE TO MY ANSWER
the easiest solution to this would be if you could save the whole code in xml.
and by this I mean if you could add the backslash (\) before the uE101
<Item>
<ItemInfo>
<Value>\uE101</Value> //see the added "\" character?
<Name>1</Name>
</ItemInfo>
</Item>
And the C# code:
data = (from query in XElement.Load("Data.xml").Descendants("ItemInfo")
select new ItemInfo
{
value = query.Element("Value").Value, //provided value is of string type
name = query.Element("Name").Value
}).ToList();
store just the HEX values, without the "u" in front like E101, not uE101, and translate them to ints....
//the conversion from STRING CONTAINING HEXADECIMAL CHARACTERS to INTEGER
//can be done by standard methods included in basic interger...
//YOUR'S doesn't work because you didn't remove the `u` in front of the HEX VALUE
//in string - and i'm also not sure about the implicit conversion between
//hexadecimal string and integer....
//so, the improved version of your code using the stuff you have now
private void OnLoaded(object sender, RoutedEventArgs e)
{
//this should work for values stored as integer
data = (from query in XElement.Load("Data.xml").Descendants("ItemInfo")
select new ItemInfo
{
value = int.Parse(query.Element("Value").Value.ToString().Substring(1),NumberStyles.HexNumber),
name = query.Element("Name").Value
}).ToList();
int itemcount = data.length;
while (itemcount-- > 0)
{
TextBlock t = new TextBlock()
{
Width = 75,
Height = 75,
Text = #"\" + data[itemcount].value,
FontFamily = new FontFamily("Segoe UI Symbol")
};
wrapPanel.Children.Add(t);
}
}
CONCLUSION
IMHO the best solution I can think of top of my head is to store the XML with the backslash in the value and when reading, having the ItemInfo class contain two strings - value and name

Custom labels on ZedGraph PieChart

I want to create custom labels on my PieChart. Currently, the type of my labels is PieLabelType.Value but I need to format the value to display a currency symbol (€) and the thousands separator.
Usually, I use the String.Format method with C0 as an argument, but I can't use PieLabelType.Value.Format("C0").
Code sample:
PieItem oTempPie1 = oGraphPane.AddPieSlice(oGerCosts._CNQ_, RedColor, 0, "blabla");
oTempPie1.LabelType = PieLabelType.Value;
PieItem oTempPie2 = oGraphPane.AddPieSlice(oGerCosts._CTQ_, BlueColor, 0, "blabla");
oTempPie2.LabelType = PieLabelType.Value;
oGraphPane.Title.Text = "RDV " + sScenarioReference;
oGraphPane.Legend.Position = LegendPos.Right;
oGraphPane.Legend.IsVisible = true;
// Font:
oGraphPane.Title.FontSpec.Size = c_fDefaultFontSize;
oGraphPane.Title.FontSpec.IsBold = true;
oGraphPane.Legend.FontSpec.Size = c_fDefaultFontSize;
How can I solve this problem?
I found a solution for my problem.
I've edited the PieItem class of ZedGraph library to add item on the Enum PieLabelType.
I've modified the code to format the return string according to the Enum value.

different format into one single line Interop.word

I've been trying to figure out how to insert 2 different formats into the same paragraph using interop.word in c# like this:
hello planet earth here's what I want to do
Assuming you have your document defined as oDoc, the following code should get you the desired result:
Word.Paragraph oPara = oDoc.Content.Paragraphs.Add(ref oMissing);
oPara.Range.Text = "hello planet earth here's what I want to do";
object oStart = oPara.Range.Start + 13;
object oEnd = oPara.Range.Start + 18;
Word.Range rBold = oDoc.Range(ref oStart, ref oEnd);
rBold.Bold = 1;
I had to modify Dennis' answer a little to get it to work for me.
What I'm doing it totally automated, so I have to only work with variables.
private void InsertMultiFormatParagraph(string text, int size, int spaceAfter = 10) {
var para = docWord.Content.Paragraphs.Add(ref objMissing);
para.Range.Text = text;
// Explicitly set this to "not bold"
para.Range.Font.Bold = 0;
para.Range.Font.Size = size;
para.Format.SpaceAfter = spaceAfter;
var start = para.Range.Start;
var end = para.Range.Start + text.IndexOf(":");
var rngBold = docWord.Range(ref objStart, ref objEnd);
rngBold.Bold = 1;
para.Range.InsertParagraphAfter();
}
The main difference that made me want to make this post was that the Paragraph should be inserted AFTER the font is changed. My initial thought was to insert it after setting the SpaceAfter property, but then the objStart and objEnd values were tossing "OutOfRange" Exceptions. It was a little counter-intuitive, so I wanted to make sure everyone knew.
The following code seemed to work the best for me when formatting a particular selection within a paragraph. Using Word's built in "find" function to make a selection, then formatting only the selected text. This approach would only work well if the text to select is a unique string within the selection. But for most situations I have run across, this seems to work.
oWord.Selection.Find.Text = Variable_Containing_Text_to_Select; // sets the variable for find and select
oWord.Selection.Find.Execute(); // Executes find and select
oWord.Selection.Font.Bold = 1; // Modifies selection
oWord.Selection.Collapse(); // Clears selection
Hope this helps someone!
I know this post is old, but it came out in almost all my searches. The answer below is in case someone, like me, wants to do this for more than one word in a sentence. In this case, I loop through a string array of variables that contain strings and change that text to bold--modifing #joshman1019
string[] makeBold = new string[4] {a, b, c, d};
foreach (string s in makeBold)
{
wApp.Selection.Find.Text = s; //changes with each iteration
wApp.Selection.Find.Execute();
wApp.Selection.Font.Bold = 1;
wApp.Selection.Collapse(); //used to 'clear' the selection
wApp.Selection.Find.ClearFormatting();
}
So, each string represented by the variable will be bold. So if a = "hello world", then Hello World is made bold in the Word doc. Hope it saves someone some time.
I know this is an old thread, but I thought I'd post here anyway for those that come across it via Google (like I did). I got most of the way to a solution with krillgar's approach, but I had trouble because some of my text contains newlines. Accordingly, this modification worked best for me:
private void WriteText(string text)
{
var para = doc.Content.Paragraphs.Add();
var start = para.Range.Start;
var end = para.Range.Start + text.IndexOf(":");
para.Range.Text = text;
para.Range.Font.Bold = 0;
para.Range.InsertParagraphAfter();
if(text.Contains(":")){
var rngBold = doc.Range(start, end);
rngBold.Bold = 1;
}
}
The key difference is that I calculate start and end earlier in the function. I can't quite put my finger on it, but I think if your new text has newlines in it, the later calculation of start/end messes something up.
And obviously my solution is intended for text with the format:
Label: Data
where Label is to be bolded.
Consider usage of Range.Collapse eventually with Microsoft.Office.Interop.Word.WdCollapseDirection.wdCollapseEnd as parameter.
That would allow next text to have formatting different than previous text (and next text formatting will not affect formatting of previous one).

Categories