I'm trying to highlight a whole line in a RichTextBox. Right now I have this method
if (Current != null)
{
selectStart = this.textBox.Text.Length;
foreach (string s in Current.Details)
{
this.textBox.AppendText(s + Environment.NewLine);
}
selectEnd = this.textBox.Text.Length;
this.textBox.Select(selectStart, selectEnd - selectStart);
this.textBox.SelectionBackColor = Color.FromArgb(51, 255, 51);
}
But this results with only highlighting the text, as shown here:
I want the code to highlight the whole line length. Is there a way to do that ?
I don't think you can do what you want to do as the RichTextBox does not support the box model (like browsers would with a <div> block). It will only ever decorate the text itself.
Related
I need to paste some rtf text from a datagrid into a flow document. I want to paste it at the caret position in the richtextbox. This works except when i have a bullet or Numbered list. It will paste it before the bullet or number.
I have searched every where for this with no luck.
private void dgStandardText_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
if (dgStandardText.SelectedItems.Count > 0) {
foreach(DataRowView row in dgStandardText.SelectedItems) {
byte[] byteArray = Encoding.ASCII.GetBytes(row[3].ToString());
using(MemoryStream ms = new MemoryStream(byteArray)) {
TextRange tr = new TextRange(txtAreaText.CaretPosition, txtAreaText.CaretPosition);
tr.Load(ms, DataFormats.Rtf);
}
}
}
NeedSave = true;
dgStandardText.SelectedItems.Clear();
}
Before Paste
After Paste
This seems to happen when the content you're pasting includes block elements, as opposed to inline elements. For plain text, WPF seems to treat newlines (e.g., \r\n) as paragraph breaks, so multi-line content would be translated into multiple blocks. What you want to do is insert just the inline content from each of those source blocks, such that it goes into the current block of the target document (in this case, a list item). Do this for the first source block, then insert a paragraph break, update the caret position, and move on to the next block.
Is the content of the grid row actually RTF content, or is it plain text? If it's plain text, then this should be pretty straightforward. Try changing your foreach loop body to something like this:
var text = row[3].ToString();
var lines = text.Split(
new[] { '\r', '\n' },
StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var p = txtAreaText.CaretPosition;
txtAreaText.BeginChange();
p.InsertTextInRun(line);
p = p.InsertParagraphBreak();
txtAreaText.EndChange();
txtAreaText.CaretPosition = p;
}
Now, if the source content really is RTF, then things will get more complicated. I suspect you'll need to load it into an in-memory flow document and walk through the elements to figure out where the paragraph breaks are. For each paragraph, locate the inline contents that intersect the selection range, and insert them into the target document. Insert a paragraph break when you reach the end of each paragraph in the source range, just like in the example above.
I'm afraid the Documents API is the one area of WPF that I haven't explored very thoroughly, so I can only give you a general idea of what to do. Perhaps someone else can provide more detail.
In JavaScript I can easily get a value from a css file. For example, the width of a certain class. This is done in the question below:
How do you read CSS rule values with JavaScript?
I want to know the CSS width value in my C# code to calculate the width of my scroll area. What I have so far is:
int toDoWidth = 100;
using (StreamReader cssFile = File.OpenText(Server.MapPath("~/Content/Tracker.css")))
{
string line = null;
while ((line = cssFile.ReadLine()) != null)
{
if (line == ".my_note {")
{
line = cssFile.ReadLine();
if (line != null)
{
line = line.Substring(line.IndexOf(":")+2);
line = line.Substring(0, line.IndexOf("px"));
toDoWidth = line.AsInt();
}
break;
}
}
}
...
My code simply does not feel right. If later in development someone changes the CSS by adding a value before width in my_note class, then my code would not work anymore...
Is there a simpler/better way to open the CSS file and read a certain property in C# code?
p.s.: I'm reading/searching since years on Stack Overflow, but I thought it's time to post my first question ;)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to prevent richTextBox to paste images within it?
If you're using Richtextbox, there are several advantages in Richtextbox for example:
we can use color font on it
Setting custom font in a region
Attach files on it.. etc
take a look at the picture:
Here is my problem:
Can i just make it text only?
In my project, attach file or the like is unnecessary at all. I even didn't want attach or paste an images on it, i just want "text only" on Richtextbox
How can i do that?
Since RichTextBox doesn't have a Images or Objects collection you have to go for the RTF formatting codes. All data of RichTextBox is stored as plain text with special formatting codes, this is exposed by the control through its RTF property. Learning this code language is essential if you want to read or change it, learning resources are easily available throughout the web, see for example this overview. RichTextBox uses more simplified rtf codes than several full-feature editors like MS Word etc, so it is usually beneficial to load data into a RTB before manipulating it, this will remove much redundant data.
Making a long story short, I found that it is necessary to search for rtf groups that start with either "pict" or "object" command. Knowing that groups may be nested you can't just find the first end-group char from there, you have to parse the string char by char while keeping count of grouping to find the end of those groups. Now you have enough information to remove that part of the string. Rtf may contain multiple picture/object groups so you have to do this until all are removed. Here is a sample function that return rtf string after removing those groups:
private string removeRtfObjects(string rtf)
{
//removing {\pict or {\object groups
string pattern = "\\{\\\\pict|\\{\\\\object";
Match m = Regex.Match(rtf, pattern);
while (m.Success) {
int count = 1;
for (int i = m.Index + 2; i <= rtf.Length; i++) {
//start group
if (rtf(i) == '{') {
count += 1;
//end group
} else if (rtf(i) == '}') {
count -= 1;
}
//found end of pict/object group
if (count == 0) {
rtf = rtf.Remove(m.Index, i - m.Index + 1);
break; // TODO: might not be correct. Was : Exit For
}
}
m = Regex.Match(rtf, pattern);
//go again
}
return rtf;
}
When should this be done? You have already mention Paste, there is also Insert, these can be trapped with the KeyDown event where you get the clipboard info and handle it accordingly. Setting e.Handled=True when you have handled the operation yourself signals that the control should not do any default processing for this key combination. This is also how you block pasting images without destroying the users clipboard. Example:
private void RichTextBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
//aware of Paste or Insert
if (e.Control && e.KeyCode == Keys.V || e.Shift && e.KeyCode == Keys.I) {
if (Clipboard.ContainsImage || Clipboard.ContainsFileDropList) {
//some images are transferred as filedrops
e.Handled = true;
//stops here
} else if (Clipboard.ContainsData(DataFormats.Rtf)) {
RichTextBox rtbox = new RichTextBox();
//use a temp box to validate/simplify
rtbox.Rtf = Clipboard.GetData(DataFormats.Rtf);
this.RichTextBox1.SelectedRtf = this.removeRtfObjects(rtbox.Rtf);
rtbox.Dispose();
e.Handled = true;
}
}
}
Yes, it is possible.
Handle Ctrl+V in RichTextBox1_KeyDown, then check the data format in the Clipboard: if data is plain text, paste it; if data is RTF, convert it to plain text (in a buffer without changing the Clipboard content) and paste it; don't paste any other type of data.
This is a partial example just to show you how to proceed:
private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.V)
{
// suspend layout to avoid blinking
richTextBox2.SuspendLayout();
// get insertion point
int insPt = richTextBox2.SelectionStart;
// preserve text from after insertion pont to end of RTF content
string postRTFContent = richTextBox2.Text.Substring(insPt);
// remove the content after the insertion point
richTextBox2.Text = richTextBox2.Text.Substring(0, insPt);
// add the clipboard content and then the preserved postRTF content
richTextBox2.Text += (string)Clipboard.GetData("Text") + postRTFContent;
// adjust the insertion point to just after the inserted text
richTextBox2.SelectionStart = richTextBox2.TextLength - postRTFContent.Length;
// restore layout
richTextBox2.ResumeLayout();
// cancel the paste
e.Handled = true;
}
}
I want to implement something that programmatically changes the background of the text when provided with a documentline.(Something that looks very similar to a block selection of a text. I'm going to be using this for debug breakpoints of an IDE I'm designing). I don't want to have to use selection as it causes the textbox to scroll.
I think I need to make use of DocumentColorizingTransformer but I'm not 100% sure how to go about this.
public class ColorizeAvalonEdit : ICSharpCode.AvalonEdit.Rendering.DocumentColorizingTransformer
{
protected override void ColorizeLine(ICSharpCode.AvalonEdit.Document.DocumentLine line)
{
int lineStartOffset = line.Offset;
string text = CurrentContext.Document.GetText(line);
int start = 0;
int index;
if (line.LineNumber == LogicSimViewCodeWPFCtrl.currentLine)
{
while ((index = text.IndexOf(text, start)) >= 0)
{
base.ChangeLinePart(
lineStartOffset + index, // startOffset
lineStartOffset + index + text.Length, // endOffset
(VisualLineElement element) =>
{
element.TextRunProperties.SetBackgroundBrush(Brushes.Red);
});
start = index + 1; // search for next occurrence
}
}
}
}
currentLine is the portion that will be highlighted.
The above code does work properly.. only problem is if the currentLine ever changes while I am viewing that line, it doesn't highlight the updated line until I scroll to another portion of the document (hiding the updated line), and come back to the updated line.
Also, how do I make the line numbers start from zero?
Since it was their creation, I peeked at SharpDevelop's source and how they did it.
They defined a bookmark type (BreakpointBookmark) and added bookmark to the line.
bookmark itself sets the color of the line in CreateMarker method. It is strange that it is not possible to configure colors of the break-point in SharpDevelop.
Hope it helps.
protected override ITextMarker CreateMarker(ITextMarkerService markerService)
{
IDocumentLine line = this.Document.GetLine(this.LineNumber);
ITextMarker marker = markerService.Create(line.Offset, line.Length);
marker.BackgroundColor = Color.FromRgb(180, 38, 38);
marker.ForegroundColor = Colors.White;
return marker;
}
I found the answer
TxtEditCodeViewer.TextArea.TextView.Redraw();
Isn't this a duplicate of this question?
However it looks like you should call InvalidateArrange() on the editor or InvalidateVisual() on each changed visual.
I'm calling a public method from another class. It takes in a List as a parameter, and goes through the list printing out each item into a text field. The problem is the text field is remaining empty!. I've checked that the list is populated by outputing the item to the console before I put it into the text box, and the text is coming up fine there.
The list contains strings, and should output each string to the textfield followed by a semi colon.
This is the method which is being called:
public void fillAttachment(List<string> attachList)
{
for (int i = 0; i < attachList.Count; i++)
{
Console.WriteLine("List: " + attachList[i]);
txtAttach.Text += attachList[i] + ";";
}
}
I would solve it in this way:
foreach(var attach in attachList)
{
Console.WriteLine(attach);
txtAttach.AppendText(string.Format("{0};", attach));
}
Setting the text property on a text box and it not displaying could be one of the following:
You are not looking at the same control as you are setting the text in
Could you have instantiated a second copy of the form object and it is this form that you are setting the txtAttach text property in?
Could the control that you are expecting to be populated be a different one? Right click the text box that you want the text to appear in click properties and check the name.
Something else is clearing the textbox after you set it
Right click the txtAttach.Text and click Find All References, this will show you all the places that the Text property is referenced - written and read - in your project. This is a very useful way to locate other interaction with this control.
Fomatting is making the text box appear empty
Is the Font too small, or in the same colour as the background. Can you select the text in the text box?
The easiest way to test all of the above is to create a new text control on your form with a different name, change your code to populate it, check that it is indeed populated, then replace the old one.
As an aside, you could also reduce the code with a single line as follows:
public void fillAttachment(List<string> attachList)
{
txtAttach.Text = String.Join(";", attachList.ToArray());
}
Although this obviously skips out the console write line function.
Not sure why yours doesn't work but I would have done it like this...
public void fillAttachment(List<string> attachList)
{
string result = "";
//OR (if you want to append to existing textbox data)
//string result = txtAttach.Text;
for (int i = 0; i < attachList.Count; i++)
{
Console.WriteLine("List: " + attachList[i]);
result += attachList[i] + ";";
}
txtAttach.Text = result;
}
Does that work for you? If not then there is something else very wrong that is not obvious from your code