How to have a fixed line spacing in a textbox? - c#

I am creating a software for note-taking. I created an image of a notebook with the lines, and etc. Now, I want to create a textbox (or rich text box, or whatever element that works) that will add the text exactly on top of each line.
However, as the user types more than a few lines, the texts gets shifted a little bit on each line, ending up very weird.
I looked through many forums and questions in trying to have this fixed. Nothing helped. I'm developing it in Visual Studio, WPF project, C#. I want to add this control to the C# code, no XAML.

Try Setting the LineStackingStrategy property.
p.LineStackingStrategy = LineStackingStrategy.BlockLineHeight;
If you need some spacing before the line also, like on starting of a paragraph then you can try setting the property as:
p.LineStackingStrategy = LineStackingStrategy.MaxHeight;
Check this Post: WPF- "LineSpacing" in a TextBlock

The following should work for line height or paragraph margins:
RichTextBox rtb = new RichTextBox();
Paragraph p = rtb.Document.Blocks.FirstBlock as Paragraph;
p.LineHeight = /* Your height here */;
p.Margin = new Thickness(/* Your height here */);

Related

DrawString and TextBox same rendering

Inside OnPaint of a form I am rendering some text on top of an image. For that I call Graphics.DrawString with word wrapping enabled. In order to be able to edit the text I occasionally show (and hide again after editing) an additional TextBox occupying the same rectangle as my hand drawn text and also with word wrapping enabled.
My idea was that the TextBox ought to render the text exactly like the DrawString command. However there appear to be small deviations of text position (and probably text size?). Moreover these deviations seem to vary depending on the chosen font so it is impossible to tune them manually.
While the deviations are not so terrible as such, they lead to irritating consequences when it comes to the automatic word wrapping. For example in the TextBox a word might appear on the second line while it might appear on the first line when rendered with DrawString after accepting the edit. Most of the time it works but for some rectangle sizes it fails.
If transparency had been available for TextBox, I would have used it instead of rendering text manually, but none of the solutions I found has worked.
Is there any hope that I can find out what settings synchronize the rendering between DrawString and TextBox ? Or is the latter an undocumented implementation detail of the win32 textbox?
The essentials of my code (g is a Graphics object from the paint event args):
stringFormat = new StringFormat(StringFormat.GenericDefault);
stringFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip;
stringFormat.Trimming = StringTrimming.None;
stringFormatAutomaticLinebreak = new StringFormat(StringFormat.GenericDefault);
stringFormatAutomaticLinebreak.FormatFlags = StringFormatFlags.NoClip;
stringFormatAutomaticLinebreak.Trimming = StringTrimming.None;
if (Data.IsAutomaticLinebreak)
{
Rectangle boundingRectangle = new Rectangle(Data.TextPosition.X, Data.TextPosition.Y,
Data.WindowSize.Width-Data.TextPosition.X-1, Data.WindowSize.Height-Data.TextPosition.Y-1);
g.DrawString(Data.Text, Data.TextFont, Data.TextBrush, boundingRectangle, stringFormatAutomaticLinebreak);
}
else
{
g.DrawString(Data.Text, Data.TextFont, Data.TextBrush, Data.TextPosition.X, Data.TextPosition.Y, stringFormat);
}
and
surrogateTextBox = new TextBox();
surrogateTextBox.BorderStyle = BorderStyle.None;
surrogateTextBox.Multiline = true;
surrogateTextBox.Text = Data.Text;
surrogateTextBox.Font = Data.TextFont;
surrogateTextBox.Location = new Point(Data.TextPosition.X,Data.TextPosition.Y);
surrogateTextBox.Size = new Size(Data.WindowSize.Width-Data.TextPosition.X-1, Data.WindowSize.Height-Data.TextPosition.Y-1);
surrogateTextBox.WordWrap = Data.IsAutomaticLinebreak;
Controls.Add(surrogateTextBox);

MigraDoc: Align text or a table at the bottom of the page above the footer

I am using MigraDoc to generate a PDF. I want to align some content to the bottom of the last page. This is boilerplate disclaimer information that my company always includes in these types of documents. The goal is to keep the content altogether and always have it appear just above the footer on the last page. If there isn't room on the last page of actual content to keep it together, there should be a page break and the boilerplate content will be on a page by itself.
I would like to do this without measuring the height of the content.
I get the impression that I can use TextFrame to assist with this in some way, but I can't find any documentation on it. The questions and examples I've found online refer to being able to "absolutely position" the TextFrame, but none of the examples seem to do that, exactly.
As a starting point, I am trying to position a paragraph of text in the way I described on an otherwise blank page. Here's my latest experiment:
static void AddBoilerPlate(Section section) {
var sectionWidth = PdfSharp.PageSizeConverter.ToSize(PageSize.Letter).Width - section.Document.DefaultPageSetup.LeftMargin.Point -
section.Document.DefaultPageSetup.RightMargin.Point;
section.AddPageBreak();
var frame = section.AddTextFrame();
frame.RelativeVertical = RelativeVertical.Page;
frame.Width = sectionWidth;
frame.Top = ShapePosition.Bottom;
frame.AddParagraph(DisclaimerText);
}
The text starts just above the footer (the blue line in this screenshot) and then runs over the footer:
Once I get a paragraph of text aligned, then I think I will be able to use a table with one column and one row instead, and then put all of my content in there.
Update: here is a screenshot showing my goal (faked using a page break and SpaceBefore):
Update: here are some related articles that don't quite get me where I'm trying to go:
Centering a table on a page using a TextFrame: http://forum.pdfsharp.net/viewtopic.php?p=753#p753
Seems to answer the same question, but doesn't provide information about how to absolutely position the TextFrame: http://forum.pdfsharp.com/viewtopic.php?f=2&t=587
Keeping table together on a page ("in one piece"). This will be useful once I figure out the issue with aligning relative to the bottom of the page: Keep table in one piece MigraDoc / PDFsharp
Update: Note that adding a height to the TextFrame does make the text align the way I need it to. It's not ideal, because I would rather not hard-code the height. But it does produce the desired effect:
static void AddBoilerPlate(Section section) {
var sectionWidth = PdfSharp.PageSizeConverter.ToSize(PageSize.Letter).Width - section.Document.DefaultPageSetup.LeftMargin.Point -
section.Document.DefaultPageSetup.RightMargin.Point;
section.AddPageBreak();
var frame = section.AddTextFrame();
frame.RelativeVertical = RelativeVertical.Page;
**frame.Height = new Unit(75, UnitType.Millimeter);**
frame.Width = sectionWidth;
frame.Top = ShapePosition.Bottom;
frame.AddParagraph(DisclaimerText);
}
Update: Note, though, that setting the TextFrame height doesn't resolve the ultimate issue. Content added before the boilerplate should push the boilerplate to the next page if there isn't enough space for it, and that's not happening.
Update: After trying it out myself (I've had the same Problem), add an invisible element with the Height you want to have just before the bottom element. In case the invisible Element doesn't fit it will seem that the page break occurred because of the bottom element.
Works like a charm.
(tip I added a border to both elements for testing so I was able to make sure the layout was proper)

Visual Studio listbox text is too long

So I'm making an application for a friend of mine. This app contains a winforms listbox. The listbox contains tweets. Everything works fine but the problem is the length of the tweets. When a tweet is too long, the listbox cuts parts away. Example:
tweetListBox:
Thow tweeted: jalskjdkljasdljlasjkdlasjdlkjaslkjaskljdlasjkd...
It adds dots when the text is too long. I can't resize the listbox because then it's too big. Is there a way to make the text that's bigger then 100 pixels split into different lines?
If you don't need the selection capabilities of a ListBox, you could switch to a multi line line text box. Use a regular text box and set the multi line property = true. Stretch the control to the appropriate size to match that of the ListBox. Add a new tweet using :
multiLineTweetBox.Append(newTweet + Environment.NewLine);
It is not possible by just setting a property like WordWrap = true, it simply doesn't exists. A solution already has been given on StackOverflow here:
Winforms DotNet ListBox items to word wrap if content string width is bigger than ListBox width?

How to control winform mschart legend text alignment c#?

How does one set the alignment of text within a chart legend object? I've tried using:
myChartName.Legends["mySeriesName"].Alignment = stringAlignment.Near
With no effect. I've also tried to create custom legend items, again resulting in no effect. Text is ALWAYS centered (along with the series marker) in the legend "box". The only text I have been able to align is the title, but I don't need titles in my application.
My research to date says the legend object is basically a table with (by default) two cells. If that is the case there should be a way to access those cells and manipulate them as table cells. So, what gives? Why can't I access the text alignment properties of the legend object? Clearly, there is something I'm missing, but for the life of me I can't seem to figure this out. Quite frustrating.
Problem solved. The CustomItem approach wasn't working either, so I tried using the LegendCellColumn Class.
I changed the LegendStyle from Column to Row, then added two CellColumns, one for the series symbol and one for the legend text. Set the alignment, margins, and column widths (that turned out to be the trick), and voila; a legend that looks like I want. Here's the code for anyone with a similar issue.
chartSel.Legends[ySeries.Name].CellColumns.Add(new LegendCellColumn("", LegendCellColumnType.SeriesSymbol, ""));
chartSel.Legends[ySeries.Name].CellColumns[0].Alignment = ContentAlignment.TopLeft;
chartSel.Legends[ySeries.Name].CellColumns[0].Margins = new System.Windows.Forms.DataVisualization.Charting.Margins(0, 0, 1, 1);
chartSel.Legends[ySeries.Name].CellColumns[0].MinimumWidth = 250;
chartSel.Legends[ySeries.Name].CellColumns[0].MaximumWidth = 250;
chartSel.Legends[ySeries.Name].CellColumns.Add(new LegendCellColumn("", LegendCellColumnType.Text, ySeries.Name));
chartSel.Legends[ySeries.Name].CellColumns[1].Alignment = ContentAlignment.MiddleLeft;
chartSel.Legends[ySeries.Name].CellColumns[1].Margins = new System.Windows.Forms.DataVisualization.Charting.Margins(0, 0, 1, 1);
chartSel.Legends[ySeries.Name].CellColumns[1].MinimumWidth = 1500;
chartSel.Legends[ySeries.Name].CellColumns[1].MaximumWidth = 1500;
It's probably not the most efficient way to do it, but it works. Technically, the legend symbol and text are still centered in the object, but because I'm forcing the widths of the two columns it has the appearance of being left-justified.
Hopefully, this may help another newbie like me avoid days of consternation.
My understanding is that Legend alignment relates to the Docking property, not really how the text is aligned within the legend. So setting Alignment to Near means positioning the legend box near the Docking direction.
It is quite hard to explain this textually. The MS Chart Samples have a subsection named Chart features -> Legends -> Style and Auto Positioning which will help you play with those two properties and understand how they are meant to work.
For inner legend alignment, you may need to use Legend.CustomItems and define LegendCell individually.
chart.Legends["Default"].CustomItems.Clear();
chart.Legends["Default"].CustomItems.Add(new LegendItem("LegendItem", Color.Red, ""));
chart.Legends["Default"].CustomItems[0].Cells.Add(new LegendCell(LegendCellType.Text, "My text", ContentAlignment.MiddleLeft));
This is described inside the Chart features -> Legends -> Legend Cells section of the samples.
While continuing to try to figure this out I stumbled on this tidbit of info from the following MSDN library page:
http://msdn.microsoft.com/en-us/library/dd456711(v=vs.100).aspx
"NOTE: You cannot adjust the individual legend items and cells in the Chart.Legends collection. To adjust them, use custom legend items."
So, back to the CustomItem route. I've got this code gleaned from several sources (including you, Dominique, thanks):
chartSel.Legends.Add(ySeries.Name);
chartSel.Series[ySeries.Name].IsVisibleInLegend = false;
chartSel.Legends[ySeries.Name].CustomItems.Clear();
LegendItem li = new LegendItem();
li.ImageStyle = LegendImageStyle.Line;
li.Cells.Add(LegendCellType.SeriesSymbol, "", ContentAlignment.TopLeft);
li.Cells[0].BackColor = Color.CornflowerBlue; //color is only to see the cell bounds
li.Cells.Add(LegendCellType.Text, ySeries.Name, ContentAlignment.TopLeft);
li.Cells[1].BackColor = Color.Aquamarine; //color is only to see the cell bounds
chartSel.Legends[ySeries.Name].CustomItems.Add(li);
From what I can find it should work, but it doesn't. It results in a legend object with two cells; the first is empty and the second has left-justified text. I tried to post an image of it, but the system says I'm not yet worthy.
Why there is no line for the series symbol is also a mystery, but that's another problem to solve. The text justification issue is my main concern at the moment. It looks like the text within the cells is left-justified as desired, but the cells themselves are centered in the legend object; not what I wanted. I want those cells to be left-justified in the object too, so the first cell is against the left edge of the legend object.
Ideas?

Prevent combobox from resizing on font change

I have a combo box that has a list of font families in it. As you can guess I'm making a toolstrip for editing fonts in a rich text box control. The problem is when I change fonts it's resizing my combobox.
scrolling through different fonts causes the combo box to become "jumpy" and some fonts have a huge height which is causing for some hilarious problems.
Exhibit A:
Exhibit B:
Yeh... I'll show the code that I have so far... by the way the combobox is just bound to the font families collection.
void box_SelectedIndexChanged(object sender, EventArgs e)
{
String text = ((Font)box.SelectedItem).Name;
Font font = (Font)box.SelectedItem;
BeginInvoke(new Action(() => box.Text = text));
BeginInvoke(new Action(() => box.Font = font));
}
Anyone have any ideas, if I can't find a solution I can just stop the font from changing and just display the name in the default font.
Using a ToolStripComboBox is the problem here I think. The .NET 2.0 ToolItem classes have a lot of residual, erm, features that never got addressed. WPF sucked the resources away. The tool strip is obviously not handling the resize very well. Nor does it make the rest of the form move down when it gets bigger which is by design.
The canonical font combobox uses owner draw to display the fonts in the dropdown list in their regular style. Without changing the font of the box itself. You really don't want the toolstrip to resize, that's just not a great UI.
The only way I can think of doing it is by creating a custom combobox control and deriving from said control. This will give you access to the variable ownerdraw which gives us a little more flexibility without having to mess around with the ItemHeight property. Hooking into one of the events, which dictate that the value of the control has changed.
You could then have a function like the following to calculate the new layout size:
using (Font font = new Font(this.Font.FontFamily, (float)this.PreviewFontSize))
{
Size textSize;
textSize = TextRenderer.MeasureText("yY", font);
_itemHeight = textSize.Height + 2;
}
I tried all these approaches with little success sadly. However I didn't realize it until today when I looked at how microsoft office implements it. They actually use the same font in the combo box for the selected item no matter what font is selected. So as much as I want to make it more custom I'm just going to use a uniform font for whatever font is shown in the selected index.

Categories