Laden...

[Solved] RichTextBox: Text formatieren & Elemente einfügen

Erstellt von userid14268 vor 12 Jahren Letzter Beitrag vor 12 Jahren 3.191 Views
U
userid14268 Themenstarter:in
1.578 Beiträge seit 2009
vor 12 Jahren
[Solved] RichTextBox: Text formatieren & Elemente einfügen

Hi,

Ich habe zZt das Problem das ich in einer RichTextBox UI Elemente an einer vorgegebenen Stelle einfügen muss. Das funktionierte soweit.
Ich Zeige erstmal wie.

(Ich habe es zum Testen mal billig nach gebaut)

Gegeben sind diese Objekte:

public class InlineElement
{
	public int Pos { get; set; }
	public string Text { get; set; }
}
public class Formatting
{
	public int Begin { get; set; }
	public int End { get; set; }
	public bool IsBold { get; set; }
}

Test Daten:

private Run CreateTextContent(string text, int from, int to)
{
	return new Run(text.Substring(from, to - from));
}

private string GetText()
{
	return "00123456000000000000";
}

private List<InlineElement> GetElements()
{
	var elements = new List<InlineElement>();
	elements.Add(new InlineElement
	{
		Pos = 5,
		Text = "variable"
	});
	return elements;
}

private List<Formatting> GetFormattings()
{
	var formattings = new List<Formatting>();
	formattings.Add(new Formatting
	{
		Begin = 2,
		End = 8,
		IsBold = true
	});
	return formattings;
}

Aufrag war als erstes nur diese "InlineElemente" als Buttons in ein Text zu packen:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
	var text = GetText();
	var elements = GetElements();

	var paragraph = new Paragraph();

	int pos = 0;
	for (int i = 0; i < elements.Count; ++i)
	{
		var element = elements[i];

		var run = CreateTextContent(text, pos, element.Pos);
		paragraph.Inlines.Add(run);
		paragraph.Inlines.Add(new Button
		{
			Content = element.Text
		});
		pos = element.Pos;
	}

	if (pos < text.Length)
	{
		var run = CreateTextContent(text, pos, text.Length);
		paragraph.Inlines.Add(run);
	}

	flowDocument.Blocks.Add(paragraph);
}

Wie man an dem ersten Bild erkennt war das soweit kein Problem. (1)
Ich habe es so gelöst indem ich den Text einfach gesplittet in Run Objekte gepackt habe.

Nun soll der Text auch noch formatiert dargestellt werden, wo und wie ist auch über die Struktur vorgeben.
Ich war beim Recherchieren auf TextRange und TextPointer gestoßen, aber da gibts nun ein Problem. Und war durch das Splitten ist die Selektion am ende verschoben (2)
(Die Testdaten sagen das die Zahlen 1-6 Bold sein sollen, wenn ich den Text nicht Splitte passt es genau)

private void Window_Loaded(object sender, RoutedEventArgs e)
{
	var text = GetText();
	var elements = GetElements();
	var formattings = GetFormattings();

	var paragraph = new Paragraph();

	int pos = 0;
	for (int i = 0; i < elements.Count; ++i)
	{
		var element = elements[i];

		var run = CreateTextContent(text, pos, element.Pos);
		paragraph.Inlines.Add(run);
		//paragraph.Inlines.Add(new Button
		//{
		//    Content = element.Text
		//});
		pos = element.Pos;
	}

	if (pos < text.Length)
	{
		var run = CreateTextContent(text, pos, text.Length);
		paragraph.Inlines.Add(run);
	}

	flowDocument.Blocks.Add(paragraph);

	var range = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
	foreach (var formatting in formattings)
	{
		var begin = range.Start.GetPositionAtOffset(formatting.Begin);
		var end = range.Start.GetPositionAtOffset(formatting.End);

		var formatRange = new TextRange(begin, end);

		formatRange.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
	}
}

Wenn ich nun das Element einfügen lass ist die Selektion noch mehr verschoben. (3)

Jemand ne Idee wie ich das Problem korrekt Löse?
Die Anzahl der Elemente, der Text und die Anzahl sowie art der Formatierung ist mir im Vorfeld unbekannt.

U
userid14268 Themenstarter:in
1.578 Beiträge seit 2009
vor 12 Jahren

Scheinbar muss ich für jedes Element was vor der Position war 5 dazu addieren.


	var range = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
	foreach (var formatting in formattings)
	{
		var begin = range.Start.GetPositionAtOffset(GetPosition(formatting.Begin, elements));
		var end = range.Start.GetPositionAtOffset(GetPosition(formatting.End, elements));

		var formatRange = new TextRange(begin, end);

		formatRange.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
	}
}

private int GetPosition(int position, List<InlineElement> elements)
{
	int count = elements.Where(e => e.Pos <= position).Count() * 5;
	return position + count;
}

Ich find das irgendwie Banane....

U
userid14268 Themenstarter:in
1.578 Beiträge seit 2009
vor 12 Jahren

Doch nicht so einfach wie ich dachte.
Sobald ich eine Formatierung hinzufüge verschiebt sich die Position immer willkürlich.

Ich habe dies hier:

foreach (var formatting in formattings)
{
	var range = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);

	var begin = range.Start.GetPositionAtOffset(GetPosition(formatting.Begin, elements), LogicalDirection.Forward);

	var end = begin.GetPositionAtOffset(formatting.End - formatting.Begin);

	var formatRange = new TextRange(begin, end);

	if (formatting.IsBold)
		formatRange.ApplyPropertyValue(TextBlock.FontWeightProperty, FontWeights.Bold);
	else
		formatRange.ApplyPropertyValue(TextBlock.FontWeightProperty, FontWeights.Normal);
}

Wenn ich diesen Text habe:

000111000111000
und ich will
000 nicht formatiert
111 Fett formatiert

Ist der verlauf so:
000111000111000
000111000111000
000111000111000
000111000111000

Wenn ich die Bolds aber immer nur einmal setzen lasse, dann passt es.
000111000111000
000111000111000

mein Ziel ist aber
000111000111000

Scheinbar ist es immer wenn eine Formatierung hinzugefügt wurde die nicht die erste ist, dann muss ich überall +2 machen. Ich weiß aber nun nicht ob das immer passt - auch mit den anderen formaten wie Italic, andere Schriftgröße usw...

U
userid14268 Themenstarter:in
1.578 Beiträge seit 2009
vor 12 Jahren

Ich fand heraus das jede Formatierung durch mit unbekannte Zeichen getrennt werden. Ich visualisiere es xaml like mal mit < und > Zeichen.

d.h.

  1. 000111000111000
  2. <000111000111000>
  3. <000><111><000111000>
  4. <000><111><000><111><000>

Bei den anderen Controls die eingefügt werden ist es ja wie angegeben immer 5
das zeige ich mal als "i"

  1. <000><111><0><i><00><111><000>

Wenn man nach jeder Formatierung 2 hinzu fügt als "MoveIndicator" (><) und für jedes "Inline Element" 5 (><x><) dann ist man auf der richtigen Seite.
Die Art der Formatierung macht kein unterschied.