Split over WPF RichTextBox into multiple controls

I am trying to get the height of the contents of a RichTextBox, and if it exceeds 500 pixels, divide it into several RichTextBoxes with a maximum height of 500 pixels.

Does anyone know how to do this? Thanks.

Edition:

by β€œsplit” I mean that content exceeding the height limit in another RichTextBox, the solution cannot simply change the appearance of the current RichTextBox due to the design features.

+4
source share
5 answers

To get content that exceeds the height limit in another RichTextBox, I would use the following approach:

private TextRange GetTopRange() { var result = textBox.GetPositionFromPoint(new Point(0, 0), true); if (result == null) return null; result = result.GetInsertionPosition(LogicalDirection.Forward); return new TextRange(result.DocumentStart, result); } private TextRange GetBottomRange() { var result = textBox.GetPositionFromPoint(new Point(textBox.ActualWidth, textBox.ActualHeight), true); if (result == null) return null; result = result.GetInsertionPosition(LogicalDirection.Backward); return new TextRange(result, result.DocumentEnd); } 

Having ranges of text, you can copy them to a new FlowDocument for another RichTextBox, truncate them ( range.Text = string.Empty ), etc.

+1
source

I played around with this RichTextBox problem a bit and it’s not easy ^^ My idea would be this:

  • Create a SplitRichTextBox CustomControl that inherits a RichTextBox (basically to get all depency properties)
  • Add the MaxContentHeight double value property to control the maximum size (in your case, 500 pixels)
  • Add the Remainders IList <RichTextBox> dependency property, which remains the current SplitRichTextBox that you remain after splitting it.
  • Customize the ControlTemplate of your SplitRichTextBox to display the contents of the SplitRichTextBox and the rest in the panel that will fit your layout requirements.
  • override the OnTextChanged method on your SplitRichTextBox.

This method retrieves the base document flowTextBox flowDocument and retrieves the paginator. Set MaxPageHeight and calculate the pages of the document.

 var flowDocument = this.Document; flowDocument.MaxPageHeight = this.MaxContentHeight; DocumentPaginator paginator = ((IDocumentPaginatorSource)flowDocument).DocumentPaginator; paginator.ComputePageCount(); 

Now you can retrieve the contents of each page thanks to the GetPage (int i) method in paginator. The first page is what you want for your first RichTextBox. The remaining pages will be used to create the Remainders dependency property.

The problem is that the pages are not directly RTF or flowDocument. You need to somehow extract the data from the page / page to find out how to split the document. I stayed here, and maybe this is not the way, but I think it's worth a try.

Good luck

+3
source

Have you tried using this code in the RichTextBox.ContentsResized event.

 Private Sub rtb_ContentsResized(ByVal sender As Object, ByVal e As System.Windows.Forms.ContentsResizedEventArgs) Handles txtQuestion.ContentsResized Dim h = e.NewRectangle.Height, w = e.NewRectangle.Width h = Math.Max(h, sender.Font.Height) h = Math.Min(h, Me.ClientSize.Height - 10 - sender.Top) h += sender.Height - sender.ClientSize.Height + 1 sender.Height = h 

End Sub

If there is alternative C # code for this, I don't know.

Also additional information. A Richtextbox control is drawn using GDI, while a Graphics.MeasureString measures a row using GDI +. therefore, "MeasureString" will not return the exact size of the string. I am afraid that you need to dig into the GDI32-API in order to get accurate results. if you are interested in using Win32 GDI API calls, see here

+1
source

I think I got your answer. Thanks for google and stackoverflow.

WPF FlowDocument can belong to only one RichTextBox. But if you use one document that can be manipulated at different points in the user interface, then there will not be two RichTextBoxes graphic images displaying one document (and cannot, because WPF will complain). But are you using one document or several? if one, read the rest; if not, then go.

Using MemoryStream and XamlReader / Writer will not work here, since we would like to save one document and reflect the changes wherever they are used, so copying them every time is not performed. Copied from Jared member from stackoverflow,

WPF controls can be "incomparable" and reparative as they wish, so just add a RichTextBox instance to the context that will be used throughout your wizard and make sure that you are free / immune to movement from page to page. It also allows you to save any styles or changes in the state of the editors on different pages of the wizard (which is probably desirable).

If it is not possible to split an instance of RichTextBox on different pages, I think there is a way to separate the document from the original RichTextBox. It seems that in order to separate the document from RichTextBox1, you must provide RichTextBox1 with a new document. You cannot set RichTextBox1.Document to null, but you can set RichTextBox1.Document to a new FlowDocument (), and I believe this will work.

From the above, a FlowDocument cannot be used by multiple RichTextBox controls directly. So, as I noted above, use the grid

 <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> 

to wrap RTB and used code

  FlowDocument doc = RTB1.Document; RTB1.Document = new FlowDocument(); RTB2.Document = doc; 

I don't know if this will share the control, but we will see the document (one) in the other RTB.

+1
source
 public void CreateNewRtb(object sender, RoutedEventArgs routedEventArgs) { var res = (ResourceDictionary)Application.LoadComponent(new Uri("/Design/Style/TextAreaStyle.xaml", UriKind.Relative)); var mcRtb = new RichTextBox {Style = (Style) res["TextBoxStyle"], Name = "Folha" + J}; RegisterName("Folha" + J, mcRtb); mcRtb.TextChanged += McRtbContentControl; var gcrd = new RowDefinition(); var gcrdspace = new RowDefinition(); gcrd.Height = new GridLength(980); GridControl.RowDefinitions.Add(gcrd); Grid.SetColumn(mcRtb, 1); Grid.SetRow(mcRtb, 1 + I); GridControl.Children.Add(mcRtb); I += 2; J++; gcrdspace.Height = new GridLength(30); GridControl.RowDefinitions.Add(gcrdspace); mcRtb.Focus(); } 

this is an easy way to control the size of the sickle mesh, and also create rtb as desired: D

-1
source

Source: https://habr.com/ru/post/1443325/


All Articles