How can I edit specific line in RichTextBox from code?
I add lines to RichTextBox
FlowDocument mcFlowDoc = new FlowDocument();
Paragraph para = new Paragraph();
para.Inlines.Add(new Run("I am a RichTextBox control line 1\n"));
para.Inlines.Add(new Run("I am a RichTextBox control line 2\n"));
para.Inlines.Add(new Run("I am a RichTextBox control line 3\n")
{
Foreground = Brushes.Red
});
mcFlowDoc.Blocks.Add(para);
RichTextBox1.Document = mcFlowDoc;
my XAML
<RichTextBox Margin="5" Name="RichTextBox1" FontSize="16" VerticalAlignment="Top"
Width="500" Height="220">
</RichTextBox>
Now I want to add a button while clicking on it (click event) the second line will change to "I finally got to do it"
Replace a line like this:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
string lineToReplace = "I am a RichTextBox control line 2";
string newLine = "I finally got to do it";
TextRange text = new TextRange(RichTextBox1.Document.ContentStart, RichTextBox1.Document.ContentEnd);
TextPointer current = text.Start.GetInsertionPosition(LogicalDirection.Forward);
while (current != null)
{
string textInRun = current.GetTextInRun(LogicalDirection.Forward);
if (!string.IsNullOrWhiteSpace(textInRun))
{
int index = textInRun.IndexOf(lineToReplace);
if (index != -1)
{
TextPointer selectionStart = current.GetPositionAtOffset(index, LogicalDirection.Forward);
TextPointer selectionEnd = selectionStart.GetPositionAtOffset(lineToReplace.Length, LogicalDirection.Forward);
TextRange selection = new TextRange(selectionStart, selectionEnd);
selection.Text = newLine;
selection.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
RichTextBox1.Selection.Select(selection.Start, selection.End);
RichTextBox1.Focus();
}
}
current = current.GetNextContextPosition(LogicalDirection.Forward);
}
}
If your text structure is always the same you can simply find required Run and change it in click handler like this:
var par = (Paragraph) RichTextBox1.Document.Blocks.FirstOrDefault();
var run = (Run) par.Inlines.Skip(1).First();
run.Text = "I finally got to do it\n";
Quick and dirty:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
TextRange textRange = new TextRange(
// TextPointer to the start of content in the RichTextBox.
RichTextBox1.Document.ContentStart,
// TextPointer to the end of content in the RichTextBox.
RichTextBox1.Document.ContentEnd
);
// get the lines of text
string[] lines =textRange.Text.Split(new[] { Environment.NewLine } , StringSplitOptions.RemoveEmptyEntries);
// get the second line
lines[1] = "I finally got to do it" + Environment.NewLine;
// build a string from the string array
StringBuilder builder = new StringBuilder();
foreach (string value in lines)
{
builder.Append(value);
}
// test the text in the RichTextbox
Paragraph para = new Paragraph();
para.Inlines.Add(new Run(builder.ToString()));
RichTextBox1.Document.Blocks.Clear();
RichTextBox1.Document.Blocks.Add(para);
}
and add line breaks properly to your document:
FlowDocument mcFlowDoc = new FlowDocument();
Paragraph para = new Paragraph();
para.Inlines.Add(new Run("I am a RichTextBox control line 1"));
para.Inlines.Add(Environment.NewLine);
para.Inlines.Add(new Run("I am a RichTextBox control line 2"));
para.Inlines.Add(Environment.NewLine);
para.Inlines.Add(new Run("I am a RichTextBox control line 3")
{
Foreground = Brushes.Red
});
mcFlowDoc.Blocks.Add(para);
RichTextBox1.Document = mcFlowDoc;
Related
I have a WPF RichTextBox and i'm trying to do is change the style:
FontFamily, FontSize, FontWeight, Color and some more.
I can change some of this values on the selected Text,
but i can't find a TextDecorationProperty
CodeExample:
TextSelection textRange = richTextBoxWpf.Selection;
if (btBold.IsChecked ?? false)
{
textRange.ApplyPropertyValue(FontWeightProperty, FontWeights.Bold);
btBold.IsChecked = true;
}
else
{
btBold.IsChecked = false;
textRange.ApplyPropertyValue(FontWeightProperty, FontWeights.Normal);
}
My code fails on set the Property:
var pens = new System.Windows.Media.Pen(System.Windows.Media.Brushes.Black, 1);
textRange.ApplyPropertyValue(TextDecoration.PenProperty, pens);
Fail Error-Message: "Die Pen-Eigenschaft ist für die Textformatierung nicht gültig."
Sorry, after a long search I found the Solution myself:
It in the Documents.Inline class:
TextSelection textRange = richTextBoxWpf.Selection;
textRange.ApplyPropertyValue(Inline.TextDecorationsProperty, TextDecorations.Underline);
I found function to print content of Wpf grid but the print is cropped.
Can anybody know why?
the function:
private void PrintTest()
{
FlowDocument document;
Window window;
CreateWindowToPrint(out document, out window);
PrintDialog printDialog = new PrintDialog();
window.Show();
IDocumentPaginatorSource dps = document;
if (printDialog.ShowDialog() == true)
{
printDialog.PrintDocument(dps.DocumentPaginator, "test");
}
}
and:
private void CreateWindowToPrint(out FlowDocument document, out
Window window)
{
document = new FlowDocument { };
var test = new PrintedTest() { DataContext = this.DataContext };
document.Blocks.Add(new BlockUIContainer { Child = test });
window = new Window {Content = document, Visibility = System.Windows.Visibility.Hidden };
}
The UserControl PrintedTest contains my grid.
I don't really have much experience with printing in WPF but I thought I would give it a try.
I could reproduce your problem, and I could not solve it so far.
But In my research I have found an alternative, which is more simple to print the Grid:
var printDialog = new PrintDialog();
var result = printDialog.ShowDialog();
if (result.HasValue && result.Value)
{
var testControl = new PrintedTest() { DataContext = this.DataContext };
printDialog.PrintVisual(testControl, "My WPF printing a DataGrid");
}
Instead of sending the PrintTest you could actually just send directly the grid.
I added a Line with C# code to my canvas, along with a context menu and attached event. I would like to rotate the Line using a context menu choice, not the menu text in the context menu:
newMenuItem1.PreviewMouseDown += new MouseButtonEventHandler((sx, ex) => {
MenuItem menuItem = (MenuItem)sx;
string theHeader = menuItem.Header.ToString();
if (theHeader.Contains("90")) {
Line ow = ex.Source as Line;
rt = new RotateTransform(90, 25, 50);
ow.RenderTransform = rt;
}
});
This code produces a null reference exception. If I substitute:
UIElement ow = ex.Source as UIElement;
The actual menu text will rotate!
Edit:
Here is more code, I am now trying originalsource too:
private void button1_Click(object sender, RoutedEventArgs e)
{
Line g = new Line();
g.Stroke = System.Windows.Media.Brushes.LawnGreen;
g.X1 = 0; g.X2 = 100;g.Y1 = 0;g.Y2 = 0;
g.HorizontalAlignment = HorizontalAlignment.Left;
g.VerticalAlignment = VerticalAlignment.Center;
g.StrokeThickness = 6;
ContextMenu k = new ContextMenu();
g.ContextMenu = k;
MenuItem newMenuItem1 = new MenuItem();
MenuItem newMenuItem2 = new MenuItem();
MenuItem newMenuItem3 = new MenuItem();
newMenuItem1.Header = "Rotate 90";
newMenuItem2.Header = "Rotate 180";
newMenuItem3.Header = "Rotate 270";
newMenuItem1.PreviewMouseDown += new MouseButtonEventHandler((sx, ex) => {
MenuItem menuItem = (MenuItem)sx;
string theHeader = menuItem.Header.ToString();
if (theHeader.Contains("90")) {
Line ow = (Line)ex.OriginalSource;
rt = new RotateTransform(90, 25, 50);
ow.RenderTransform = rt;
}
});
g.ContextMenu.Items.Add(newMenuItem1);
g.ContextMenu.Items.Add(newMenuItem2);
g.ContextMenu.Items.Add(newMenuItem3);
Canvas.SetTop(g, 18);
Canvas.SetLeft(g, 18);
MyCanvas.Children.Add(g);
///////
I also tried:
private static T FindAncestor<T>(DependencyObject current)
where T : DependencyObject
{
do
{
if (current is T)
{
return (T)current;
}
current = VisualTreeHelper.GetParent(current);
}
while (current != null);
return null;
}
but it does not work. My next plan is to get coordinates off the canvas, and try to determine what control sits there. This will become tricky though if an object is transformed, because I believe the UI sees it at the original position. I've experimented with other controls as well, like the TextBox and get similar issues.
A really quick and dirty way to do this would be to add your line to the menu item's tag property and retrieve it in the PreviewMouseDown handler
When creating your context menu:
newMenuItem1.Tag = g;
In you handler:
Line ow = ((FrameworkElement)ex.Source).Tag as Line;
The less quick and dirty way to do this would be to use the ContextMenuOpening event on your line as that should be sent with the sender equal to the control itself. You could then store a reference to the line somewhere and retrieve it again in the menu item click event. This works better when you have multiple lines (which I'm guess is what you intend) and just one context menu (instead of producing a bunch of copies of the same menu as you are doing now).
This is kind of a weird problem I am having right now. What I am trying to do is animate a Run element to essentially flash/blink. The parent is a Hyperlink which contains multiple Inlines of type Run and Image. Now I am trying to animate the Foreground color of the element but it does not seem to work.
Here is my code for a hyperlink.
CallbackHyperLink callbackLink = new CallbackHyperLink();
ToolTipService.SetShowDuration(callbackLink, 3600000);
ToolTipService.SetInitialShowDelay(callbackLink, 0);
callbackLink.Foreground = new SolidColorBrush(Colors.Magenta); // Default text color of the link
callbackLink.TextDecorations = null; // Disable the underline until mouse over
callbackLink.ToolTip = f.Tooltip; // Set the tooltip string
DoubleAnimation opacityAnim = new DoubleAnimation();
opacityAnim.From = 1.0;
opacityAnim.To = 0.0;
opacityAnim.FillBehavior = FillBehavior.Stop;
opacityAnim.Duration = TimeSpan.FromSeconds(BlinkDurationOff);
opacityAnim.AutoReverse = true;
_blinkAnimation.Children.Add(opacityAnim);
Storyboard.SetTarget(opacityAnim, callbackLink.Foreground);
Storyboard.SetTargetProperty(opacityAnim, new PropertyPath(SolidColorBrush.OpacityProperty));
_blinkAnimation.Stop();
_blinkAnimation.Begin();
So that gets put in a storyboard which get fired. However the foreground is not getting animated and I am not seeing any warnings that im trying to animate something I shouldn't. Anybody have any ideas?
Thanks
This works:
Storyboard.SetTarget(opacityAnim, callbackLink);
Storyboard.SetTargetProperty(opacityAnim, new PropertyPath(UIElement.OpacityProperty));
Edit full working example with a TextBlock stolen from here :
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
TextBlock callbackLink = new TextBlock();
callbackLink.HorizontalAlignment = HorizontalAlignment.Center;
callbackLink.VerticalAlignment = VerticalAlignment.Center;
callbackLink.Text = "Test";
this.Content = callbackLink;
NameScope.SetNameScope(this, new NameScope());
var b = new SolidColorBrush(Colors.Magenta);
callbackLink.Foreground = b;
this.RegisterName("MyAnimatedBrush", b);
DoubleAnimation opacityAnimation = new DoubleAnimation();
opacityAnimation.To = 0.0;
opacityAnimation.Duration = TimeSpan.FromSeconds(0.5);
opacityAnimation.AutoReverse = true;
opacityAnimation.RepeatBehavior = RepeatBehavior.Forever;
Storyboard.SetTargetName(opacityAnimation, "MyAnimatedBrush");
Storyboard.SetTargetProperty(
opacityAnimation, new PropertyPath(SolidColorBrush.OpacityProperty));
Storyboard mouseLeftButtonDownStoryboard = new Storyboard();
mouseLeftButtonDownStoryboard.Children.Add(opacityAnimation);
callbackLink.MouseEnter += delegate(object sender2, MouseEventArgs ee)
{
mouseLeftButtonDownStoryboard.Begin(this, true);
};
callbackLink.MouseLeave += delegate(object sender2, MouseEventArgs ee)
{
mouseLeftButtonDownStoryboard.Stop(this);
};
}
Also another way to link to the foreground opacity call without registering the name of the brush is the following.
Storyboard.SetTarget(opacityAnim, callbackLink);
Storyboard.SetTargetProperty(opacityAnim, new PropertyPath("Foreground.Opacity"));
This seems to finally work for me. Still tweaking my solution as I am doing a lot of Stop/Begin calls on the animation which I believe is not good way of doing things.
I am attempting to highlight text in a databound ListBox and highlight matching strings exactly like the email application on Windows Phone 7.
The search button pulls up a Popup, and on the TextChanged event, I'm filtering from a master list and re-setting the DataContext:
private void txtSearch_TextChanged(object sender, TextChangedEventArgs e)
{
results = allContent.Where(
x => x.Content.Contains(txtSearch.Text)
).ToList();
DataContext = results;
}
That part works great. The problem is with highlighting the matched text. I've tried iterating over the ListBoxItems in various events (Loaded, ItemsChanged) but they're always empty.
Any ideas about how text highlighting might be done in a databound ListItem's child TextBox?
Here is the solution that I went with:
private void ResultsText_Loaded(object sender, RoutedEventArgs e)
{
var textBlock = sender as TextBlock;
if (txtSearch.Text.Length > 0 && textBlock.Text.Length > 0)
{
BoldText(ref textBlock, txtSearch.Text, Color.FromArgb(255, 254, 247, 71));
}
}
public static void BoldText(ref TextBlock tb, string partToBold, Color color)
{
string Text = tb.Text;
tb.Inlines.Clear();
Run r = new Run();
r.Text = Text.Substring(0, Text.IndexOf(partToBold));
tb.Inlines.Add(r);
r = new Run();
r.Text = partToBold;
r.FontWeight = FontWeights.Bold;
r.Foreground = new SolidColorBrush(color);
tb.Inlines.Add(r);
r = new Run();
r.Text = Text.Substring(Text.IndexOf(partToBold) + partToBold.Length, Text.Length - (Text.IndexOf(partToBold) + partToBold.Length));
tb.Inlines.Add(r);
}