Broken tables in RichTextBox control (word wrap) [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why isn’t the richtextbox displaying this table properly?
We are having problems with the Windows.Forms.RichTextBox control in Visual Studio 2008.
We are trying to display text supplied as an RTF file by a 3rd party in a windows forms application (.NET 3.5). In this RTF text file there are tables, which contain text that spans multiple lines. The RTF file displays correctly when opened with either WordPad or Word 2003.
However, when we load the RTF file into the RichTextBox control, or copy & paste the whole text (including the table) into the control, the table does not display correctly - the cells are only single line, without wrapping.
Here are links to images showing the exact problem:
Correctly displayed in WordPad
Incorrectly displayed in RichTextBox control
I have googled for solutions and 3rd party .net RTF controls without success. I have found this exact problem asked on another forum without an answer (in fact that's where the link to the images come from) so I'm hoping stack overflow does better ;-)
My preferred solution would be to use code or a 3rd party control that can correctly render the RTF. However, I suspect the problem is that the RichTextBox control only supports a subset of the full RTF spec, so another option would be to modify the RTF directly to remove the unsupported control codes or otherwise fix the RTF file itself (in which case any information as to what control codes need to be removed or modified would be a huge help).

The Rich Text box from .NET is extremely buggy.
In RTF, the way a table is defined is actually quite different from what you could expect if you are used to HTML.
HTML:
<table>
<tr>
<td>Mycell</td>
</tr>
</table>
In RTF, a table is simply a series of paragraphs with control words defining rows, cells, borders. There is no group tag for the start/end of a table.
RTF:
\trowd\trgraph \cellx1000 Mycell \cell\row\pard\par
If you want to add a paragraph inside a cell, you use \par and the control \intbl (in table) to indicate the paragraph is inside the table.
.NET RTB can handle only a very small subset of RTF control words and doesn't support the vast majority of available commands. By the looks of things, \intbl is part of the long long list of control words it doesn't support, and if it actually parses \par at that point, the display is trashed.
Unfortunately, I don't have a solution for that but I hope the small explanation above helps you make some sense of the problem.
Don't put too much faith on my RTF sample. It works, but it's absolutely bare-bones. You can download the RTF specifications from Microsoft's website:
Word 2007 RTF specs.

Can you use the old COM control instead of the new .NET control, or do you require a "pure" .NET solution?
In other words, go into the Visual Studio toolbox, right click, choose "Choose Items", look in the COM Components tab and check Microsoft Rich Textbox Control 6.0.

Answering my own question here, but only due to the help from Joel and sylverdrag...
The short answer is that both the .Net and underlying COM RichTextBox do not support word wrap in tables. I ended up knocking up a test application and using both the COM and .Net RichTextBox controls and they both exhibited the same (broken) behaviour.
I also downloaded the RTF spec from the link supplied by sylverdrag and after tinkering with hand-made RTF documents in MS Word and RichTextEdit controls, I can confirm that TichTextBox does not correctly support the \intbl control word - which is required for word wrap in tables.
There appear to be three possible solutions:
Use TX Text Control. I have confirmed this works using a trial version but it is expensive - prices start at US$549 per developer.
Use an embedded MS Word instance as discussed on Code Project. Note that the code example provided on Code Project didn't work out of the box but I did get it working with Office 2003 & VS 2008. After much mucking around we hit an unexpected show stopper - we want the document to be read-only so we Protect() the document. While this works, when a user tries to edit the document the MS Word "Protect Document" side bar pops out from the right hand side of the control. We can't live with this and I was not able to turn it off (and from googling it looks like I'm not alone).
Give up on RTF and use HTML instead and then render the document in a WebBrowser control instead of a RichTextEdit control. That is the option we are taking as it turns out the source document is available in either format.

Step 1, Use the old COM Microsoft Rich Textbox Control 6.0;
Step 2, Make a copy of Windows\System32\MsftEdit.dll and then rename it to riched20.dll;
Step 3, Copy riched20.dll to your app folder such as bin\bebug.
This works fine, table displays correctly.

Wordpad is generally a very thin wrapper over the rich edit control, so if it appears properly there then Windows should be able to handle it.
Perhaps you're instantiating the wrong version of the rich edit control? There have been many, and Windows continues to supply the older ones for backwards compatibility. http://msdn.microsoft.com/en-us/library/bb787873(VS.85).aspx

Just create a new Control. It works fine for me.
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class RichTextBox5 : RichTextBox {
private static IntPtr moduleHandle;
protected override CreateParams CreateParams {
get {
if (moduleHandle == IntPtr.Zero) {
moduleHandle = LoadLibrary("msftedit.dll");
if ((long)moduleHandle < 0x20) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not load Msftedit.dll");
}
CreateParams createParams = base.CreateParams;
createParams.ClassName = "RichEdit50W";
if (this.Multiline) {
if (((this.ScrollBars & RichTextBoxScrollBars.Horizontal) != RichTextBoxScrollBars.None) && !base.WordWrap) {
createParams.Style |= 0x100000;
if ((this.ScrollBars & ((RichTextBoxScrollBars)0x10)) != RichTextBoxScrollBars.None) {
createParams.Style |= 0x2000;
}
}
if ((this.ScrollBars & RichTextBoxScrollBars.Vertical) != RichTextBoxScrollBars.None) {
createParams.Style |= 0x200000;
if ((this.ScrollBars & ((RichTextBoxScrollBars)0x10)) != RichTextBoxScrollBars.None) {
createParams.Style |= 0x2000;
}
}
}
if ((BorderStyle.FixedSingle == base.BorderStyle) && ((createParams.Style & 0x800000) != 0)) {
createParams.Style &= -8388609;
createParams.ExStyle |= 0x200;
}
return createParams;
}
}
// P/Invoke declarations
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr LoadLibrary(string path);
}

This is not a issue of RitchText Control provided in .net . some Ritchtext rules (Ritchtext Synatax) has been changed in new version of Ms-office (2007). however the component used in .net cannot update to cater the new rules so the issue occours.
Anand

Related

Office word editor control for WinForms Applications

I know that this question may be very old and classic but, I am trying to find a free and good word editor control to be embedded into my application for educational purpose, so I googled and tried a lot of editors and methods like using RichTextBox control and fill the RTF value with my word document data and it was displayed into the RichTextBox but without any editing capabilities that exist in the real Word application.
I just need some of the editing capabilities that are exist in the word not all of them, so I decided to build my own word editor but actually I can't find a good way to start that and I don't have that experience, Any Ideas?
What I did until now is very basic and I need to know for example how to add a new method to attach word document to my editor so I need to do something like
wordEditor1.Word = {Path of word document}
and this step should show the document inside my editor with all styles and formats just like opening any word document inside word application.
Also I need to add capability of applying paragraph style or character style on the selected paragraph, so I think that I need to add methods for characters or paragraphs like
selectedParagraph.Style = {name of style in word or name of selected style form styles pane}
Finally I need to allow user to run macros on the opened document and I know that this may be the hardest step, so I just need some ideas to redirect me to the best way of how to do that.
What I did till now is something like
using System.Windows.Forms;
namespace AutoStyle
{
public partial class WordEditor : RichTextBox
{
public WordEditor()
{
InitializeComponent();
}
public object Word
{
get;
set;
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
}
}
I believe that this question may help others like me who is newbie and has a lack of experience, so I appreciate you comments and efforts.

Restart List Numbering with C# Word Interop

I have a Word 2010 template with some bookmarks and styles that I must use to generate a Word document, after getting the information from some XMLs, and I'm using c# with the Interop (version 8.3). The template was given to me and I can't change it at all, as it follows the documentation rules of the company.
Sometimes, when I use the custom Numbered List style of the template, the numbering screws up, inexplicably starting at 2 instead of 1. Other times, it follows the numbering of the previous list, when I don't always want that to happen.
Fixing those cases would be easy if I could modify the existing styles from the template, or applying custom styles with ContinuePreviousList: false from my program, but the generated Word document must have the styles they force me to use.
If I open the Word document, right click over the list and choose "Restart at 1" option (I don't have Word in English, hope that's the proper translation), it fixes most of the problems that I might have, but I don't know how to use that from Interop. I have recorded macros and then translated to c# to know how Word makes some functions, but the mouse is locked when I start recording macros. Any ideas?
The mouse is locked, but you can use the right click mouse button on the keyboard to get the context menu, and then select Restart at 1 while recording your Macro.
I ended up with this using C# interop:
using System.Runtime.InteropServices;
using MSWord = Microsoft.Office.Interop.Word;
namespace ResetNumberingInWordDoc
{
class Program
{
static void Main()
{
var application = new MSWord.Application();
var document = application.Documents.Open(#"C:\mydocument.docx");
const int listNumber = 1; //The first list on the page is list 1, the second is list 2 etc etc
document.Range().ListFormat.ApplyListTemplateWithLevel(
ListTemplate: document.ListTemplates[listNumber],
ContinuePreviousList: false,
ApplyTo: MSWord.WdListApplyTo.wdListApplyToWholeList,
DefaultListBehavior: MSWord.WdDefaultListBehavior.wdWord10ListBehavior);
document.Save();
document.Close();
application.Quit();
Marshal.ReleaseComObject(application);
}
}
}
I found out the exact way of performing the "Restart at 1" function looking at a recorded macro. Once you have located the paragraph with the numbered list style, you have to select the number that you want to "restart at 1" and apply the "List_Norm" style:
listParagraph.SelectNumber(); //Select numbers from the NumberList paragraph
application.Selection.set_Style(document.Styles["List_Norm"]); //Apply "List_Norm" style
That way, the content of the list will keep the original style(s), but the list will start from 1.
The same code can be applied to restart the Title styles, but applying the "Tit_List" style instead of "List_Norm".

Replacing Content Controls in OpenXML

I need something as a placeholder. I at first looked to Content Control as a solution but I'm having some problems with it.
I then looked into adding CustomXML to the .docx but turned away from that because of the i4i lawsuit.
Then I decided I would just plain change the text of the Content Control through OpenXML SDK 2.0 but even if it's so marked the Content Control doesn't go away. I guess that it doesn't know that the text changed unless it happens inside word.
I could perhaps just remove the CC and place text instead but I'm afraid of problems with format and styles it could bring and also it would kind of defy the purpose of the Content Control.
Then I started wondering if I could define my own placeholders that Word could recognize. Through Building blocks perhaps. It doesn't have to do anything except be easy to find using OpenXML and somehow taggable so I know what to replace it with. I'm not really sure what can be done with Building Blocks but I'm hoping it's do-able.
Not sure what solution would be best for me but what I need is:
a)Something that's easy to place in the template, perhaps predefined Content Control placeholders that you can place where you wan't and style as you like.
b)When the data has been added it removes all placeholders, it won't be modified again. It keeps the style/format defined in the placeholder.
TO RECAP, I need answer to either
How can I edit Content Controls in OpenXML SDK so they will be removed after text is added.
-OR-
Can I define my own custom OpenXML tag for a Word Document that I could then replace?
Perhaps this can help you,
private void DeleteSdtBlockAndKeepContent(MainDocumentPart mainDocumentPart, string sdtBlockTag)
{
List<SdtBlock> sdtList = mainDocumentPart.Document.Descendants<SdtBlock>().ToList();
SdtBlock sdtA = null;
foreach (SdtBlock sdt in sdtList)
{
if (sdt.SdtProperties.GetFirstChild<Tag>().Val.Value == sdtBlockTag)
{
sdtA = sdt;
break;
}
}
OpenXmlElement sdtc = sdtA.GetFirstChild<SdtContentBlock>();
OpenXmlElement parent = sdtA.Parent;
OpenXmlElementList elements = sdtc.ChildElements;
var mySdtc = new SdtContentBlock(sdtc.OuterXml);
foreach (OpenXmlElement elem in elements)
{
string text = parent.FirstChild.InnerText;
parent.Append((OpenXmlElement)elem.Clone());
}
sdtA.Remove();
}
Take a look at using a Field. The mail merge fields are designed for exactly this purpose.
I don't understand from your question if you are only interested in a solution that automatically removes the ContentControl/SDT when you modify it using the OpenXML SDK, or whether you want it to disappear after the content is modifed programmatically or by a user.
If the former, I think you'll have to remove it yourself as Bilel suggested. If the latter, you should look at this property: ContentControl.Temporary ("the ContentControl is automatically deleted when the user types in the control, or when the text in the control is changed programmatically. When the ContentControl is automatically deleted from the document, the text in the control remains in the document.")

Get highlighted text from active window

I would like to know how can I get highlighted text from any window for example: (excel, ie, firefox,…).
please note that the following message not work in the above application
WM_GETTEXT,WM_COPY,EM_GETSELTEXT.
I have also tried control C (copy) and get selected text from clipboard but it is not a good idea.
Language used: C#
I haven't tried it myself, but the Microsoft UI Automation API should have the functionality that you need.
The UI Automation API is what you would use if you were building a screen reader to assist blind people. So it should definitely be able to access the selected text in an arbitrary application.
A good place to start would be with the "Text Pattern Overview" at http://msdn.microsoft.com/en-us/library/ms745158.aspx
Also keep your eye on question 517694. I think you'll find that answers to that question will solve your problem.
No answers huh? Well, I know you can get it from Excel, Word etc using interop. Look into that. It might give you som ideas on how to proceed with ie and ff. But basically the recieving application must have some sort of fascility for letting you do this and I don't think there's any general way which works all the time.
There is no general purpose answer to this question. Each window class will have a different solution.
For instance, if the hilighted text is in an edit window, then you can use EM_GETSEL to get the range of the selection, then WM_GETTEXT to get the text (and then throw the unselected part a way) or EM_LINEFROMCHAR to turn that range into line indexes, and then EM_GETLINE to get the selected text one line at a time.
But this won't work for any other window class.
No need to write this in C# from scratch. What's wrong with using the clipboard? This script ensures that it restores what was on the clipboard when it has finished.
Autohotkey makes this much simpler.
; Hotkey: Ctrl Shift t
^!t::
; Remember what was in the clipboard
clipboardPrev = %clipboard%
; Clear the clipboard
clipboard:=
Sleep,200
; Send a Ctrl C to copy the current selection
SendInput, {Ctrl down}c{Ctrl up}
Sleep,200
; Get the current selection from the clipboard
selectedText=%Clipboard%
if SelectedText =
{
; If the first attempt didn't get any test, try again
Sleep,200
; Send a Ctrl C to copy the current selection
SendInput, {Ctrl down}c{Ctrl up}
; Get the current selection from the clipboard
selectedText=%Clipboard%
}
; Restore the clipboard
clipboard=%clipboardPrev%
MsgBox, %selectedText%
return

Broken hyperlinks in RTF file in RichTextBox

I'm using a RichTextBox to display an RTF file, which includes a single hyperlink. The link text is not a URL (the target is a valid URL). The RTF was created with Word. Both Word and WordPad properly recognize the links (WordPad does not launch the links, but shows the appropriate hand cursor).
When I load the RTF into a RichTextBox the links appear formatted correctly (blue and underlined), but rather than behaving like a link, when the cursor moves over the link it remains an I-beam, the LinkClicked event will not fire, and it actually shows the target between angle brackets after the link (this does not seem correct). Since the link text is not a URL, DetectUrls does not help here.
Is there a reason that RichTextBox does not properly handle these links, or a way to make them work as expected?
Here is the code.
TipView.Rtf = tips[tipIndex];
// I've also tried TipView.LoadFile, with identical result
To reproduce the issue, create an RTF document with Word (I'm using 2000) containing one link whose text is not a URL but targets a valid URL, and programatically load the .rtf file into a RichTextBox (I'm using .NET 2.0 in C# Express 2008).
To support hyperlinks, you need RICHEDIT50W version of "rich edit".
For that:
Either use .NET Framework 4.7, which uses RICHEDIT50W natively in RichTextBox.
In older versions of .NET Framework, you can modify RichTextBox to use RICHEDIT50W:
public class ExRichText : RichTextBox
{
[DllImport("kernel32.dll", EntryPoint = "LoadLibraryW",
CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr LoadLibraryW(string s_File);
protected override CreateParams CreateParams
{
get
{
var cp = base.CreateParams;
LoadLibraryW("MsftEdit.dll");
cp.ClassName = "RichEdit50W";
return cp;
}
}
}
Based on RichTextBox Selection Highlight and RichTextBox cannot display Unicode Mathematical alphanumeric symbols.
Once you upgrade to RICHEDIT50W, you might need an additional fix:
Some hyperlinks don't trigger the LinkClicked event when loading a file into RichTextBox

Categories