WPF RichTextBox - Selected Block? - c#

I am experimenting with the WPF RichTextBox and notice that I can itterate through the blocks that make up its document by looping through RichTextBox.Document.Blocks.
What is the best way to get the Block that surrounds the caret?
I can get the CaretPosition and the ElementStart and ElementEnd properties of each block but can't see how to compare them because the actual character offsets are not exposed unless I am missing something obvious.

var curCaret = richTextBox1.CaretPosition;
var curBlock = richTextBox1.Document.Blocks.Where(x => x.ContentStart.CompareTo(curCaret) == -1 && x.ContentEnd.CompareTo(curCaret) == 1).FirstOrDefault();

Answer above probably works in WPF RTB but not in Silverlight 4.0. Most likely SL doesn't allow access to the Document protion of the RTB. So you have to do it via Reflection....
Something like this:
Set up a TextSelectionChanged Event Handler
Grab the TextSelection Pointer and find the Start TextPointer
Grab the TextSelection.Start.Parent item
Find out if it is of type paragraph
Parse the Paragraph.Inlines
Look for type of InlineUIContainer you need a cast it accordingly.

In Silverlight5 get the properties to be used to update a toolbar:
private void rtb_SelectionChanged(object sender, RoutedEventArgs e)
{
TextSelection ts = rtb.Selection;
object property;
property = ts.GetPropertyValue(Run.FontWeightProperty);
System.Windows.FontWeight fontWeight = property is System.Windows.FontWeight ? (FontWeight)property : FontWeights.Normal;
property = ts.GetPropertyValue(Run.FontStyleProperty);
System.Windows.FontStyle fontStyle = property is System.Windows.FontStyle ? (FontStyle)property : FontStyles.Normal;
TextDecorationCollection textDecorations = ts.GetPropertyValue(Run.TextDecorationsProperty) as TextDecorationCollection;
bool isUnderlined = textDecorations != null;
double? fontSize = ts.GetPropertyValue(Run.FontSizeProperty) as double?;
SolidColorBrush foreground = ts.GetPropertyValue(Run.ForegroundProperty) as SolidColorBrush;
Color foregroundColor = foreground != null ? foreground.Color : Colors.Black;
System.Diagnostics.Debug.WriteLine("fontweight:{0}, fontStyle:{1}, Underline:{2}, size:{3}, color:{4}",
fontWeight,
fontStyle,
isUnderlined,
fontSize,
foregroundColor);
if (fontSize.HasValue)
SetToolbarFontSize(fontSize.Value);
SetToolbarFontColor(foregroundColor);
}

Paragraph currentParagraph = richTextBox1.CaretPosition.Paragraph;
This code will return a Paragaph object and instead of a Block object but because the blocks in a RichTextBox are typically paragraphs this will not pose any problem.
MS Docs:
The Blocks property is the content property of RichTextBox. It is a collection of Paragraph elements.

Related

How to make group box text alignment center in win forms?

I am using a group box and there are several controls inside this.
My requirement is to set the group box title to the middle of the group box instead of Left.
How?
you can extend the group box class like this.
public class CustomGrpBox : GroupBox
{
private string _Text = "";
public CustomGrpBox()
{
//set the base text to empty
//base class will draw empty string
//in such way we see only text what we draw
base.Text = "";
}
//create a new property a
[Browsable(true)]
[Category("Appearance")]
[DefaultValue("GroupBoxText")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public new string Text
{
get
{
return _Text;
}
set
{
_Text = value;
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
//first let the base class to draw the control
base.OnPaint(e);
//create a brush with fore color
SolidBrush colorBrush = new SolidBrush(this.ForeColor);
//create a brush with back color
var backColor = new SolidBrush(this.BackColor);
//measure the text size
var size = TextRenderer.MeasureText(this.Text, this.Font);
// evaluate the postiong of text from left;
int left = (this.Width - size.Width) / 2;
//draw a fill rectangle in order to remove the border
e.Graphics.FillRectangle(backColor, new Rectangle(left, 0, size.Width, size.Height));
//draw the text Now
e.Graphics.DrawString(this.Text, this.Font, colorBrush, new PointF(left, 0));
}
}
add the above class into your project and use "CustomGrpBox" instead of "GroupBox" which will be created after build in your tool box.
and you can set the text any time like this.
private void Form2_Load(object sender, EventArgs e)
{
customGrpBox1.Text = "Hello World";
}
it will look like this in design time visual studio
Unfortunately, you may set the title on the right by using the RightToLeft property, but there is no property to set it in the middle.
What you can do is to set an empty Text in your GroupBox, create a Label with the title and put that label above the GroupBox (with the same parent).
You may do it dynamically at form initialization by calling following procedure:
private void CenterGroupBoxTitle(GroupBox groupbox)
{
Label label = new Label() ;
label.Text = groupbox.Text ;
groupbox.Text = "" ;
label.Left = groupbox.Left+(groupbox.Width-label.Width)/2 ;
label.Top = groupbox.Top + 2 ; // 2 is an example : adjust the constant
label.Parent = groupbox.Parent ;
label.BringToFront() ;
}
Try to create a custom control using Panel as container and draw border around this, you can then have full control of the title's alignment.
If you would like a simple approach, you can leave the groupbox's title as empty text, and then place a label at the center position of the groupbox. You can also define this as user-control so you wouldn't need to do this repeatedly.
Not an eloquent solution, but if you have a simple GroupBox, that stays the( same size, you can just pad the beginning, and the end with spaces.
example : GroupBox.Text = " This is the groupbox text ";
The amount of padding of space's will depend on the length of the box.
Of course you'll lose some of the GroupBox's beginning and end lines on top, and if that's important, then Answer 3 seems like a good solution.

Set color of a textbox programatically in a WPF application

In trying to set the color of a text box in my WPF application I did
Why do I get that error ?
And how to rectify it ?
It's telling you right in the error. The Background property is of type System.Windows.Media.Brush, not System.Windows.Media.Color, so you can't assign a Color to it.
Pass a Brush into your method instead of a Color, and assign that to the Background property.
public void addToStackPanel(string argBuiltAlarm, Brush brush)
{
...
TextBox textBox = new TextBox { Background = brush };
...
textBox1.Background = Brushes.Blue;
textBox1.Foreground = Brushes.Yellow;
You can do like this.

Getting child entity as a type?

I'm trying to dynamically create objects, and then call from them later. For example...
for(int i=0;i<10;i++)
{
tabControl.TabPages.Add(i, i.ToString());
richTextBox rtb = new richTextBox();
rtb.Parent = tabControl.TabPages[i];
rtb.dock = fill;
}
then later in my coding..
private void onButtonClick_example()
{
var rtb = tabControl.SelectTab.GetChildrenByPoint(new point(1,1));
rtb.WordWrap = true;
}
How can I return that child as a "rich text box" again?
If GetChildrenByPoint returns something other than RichTextBox, then you need to use as and check for null so you don't crash when other controls are encountered.
foreach(var item in tabControl.SelectTab.GetChildrenByPoint(new point(1,1)))
{
RichTextBox rtb= item as RichTextBox;
if(rtb != null) //if we found a RichTextBox
{
rtb.WordWrap = true;
}
}
Add a dynamic ID to your rich text box control when you create it.
Loop through the controls in the selected tab:
foreach(var control in tabControl.SelectTab.Controls)
{
if(control.ID == "NEWCONTROLID")
{
RichTextBox rtb = (RichTextBox) control;
}
}
Did this off the top of my head, so there may be code issues, but hopefully it puts you on the path. Basically you need to search for the control you created in the controls collection of the selected tab, then cast it as a RichTextBox.
You could also use Control.Find() method to find your control and then cast it.

How to change property of many buttons in WP7 using Foreach?

I want to change the property Background of many Buttons in WP7.
Can I write something like this:
Foreach (var item in (this.Content as Panel).Children)
{
If (Element is Button)
{
Element.Background = Color.red;
}
}
But this doesen't work,
Element.Background doesen't exist...
Anyone know how to fix it???
try this
//to be on the safe side first check
if(this.Content == null || !(this.Content is Panel)
return;
foreach (var item in (this.Content as Panel).Children)
{
if (item is Button)
{
Button b = item as Button;
b.Background = new SolidColorBrush(Colors.Red);
}
}
Can you try it with
Element.BackColor = Color.Red
instead of
Element.Background = Color.Red
Instead of looping through the controls, try binding their BackColor properties to something, be it a class that implements INotifyPropertyChanged with a property that returns a SolidColorBrush, another control's BackColor property, or whatever you choose to bind to. This can be done in silverlight without having to loop through the controls. Let the system manage the control appearance instead of writing it yourself.

Setting WPF text to TextBlock

I know that TextBlock can present a FlowDocument, for example:
<TextBlock Name="txtFont">
<Run Foreground="Maroon" FontFamily="Courier New" FontSize="24">Courier New 24</Run>
</TextBlock>
I would like to know how to set a FlowDocument that is stored in a variable to a TextBlock.
I am looking for something like:
string text = "<Run Foreground="Maroon" FontFamily="Courier New" FontSize="24">Courier New 24</Run>"
txtFont.Text = text;
However, The result of the code above is that the XAML text is presented unparsed.
EDIT: I guess my question was not clear enough. What I'm really trying to achive is:
The user input some text into a RichTextBox.
The application saves the user input as FlowDocument from the RichTextBox, and serializes it to the disk.
The FlowDocument is deserialized from the disk to the variable text.
Now, I would like to be able to present the user text in a TextBlock.
Therefore, as far as I understand, creating a new Run object and setting the parameters manually will not solve my problem.
The problem is that serializing RichTextBox creates Section object, which I cannot add to TextBlock.Inlines. Therefore, it is not possible to set the deserialized object to TextProperty of TextBlock.
create and add the object as below:
Run run = new Run("Courier New 24");
run.Foreground = new SolidColorBrush(Colors.Maroon);
run.FontFamily = new FontFamily("Courier New");
run.FontSize = 24;
txtFont.Inlines.Add(run);
I know that TextBlock can present FlowDocument
What makes you think that ? I don't think it's true... The content of a TextBlock is the Inlines property, which is an InlineCollection. So it can only contain Inlines... But in a FlowDocument, the content is the Blocks property, which contains instances of Block. And a Block is not an Inline
If your FlowDocument has been deserialized, it means that you have an object of type FlowDocument, right? Try setting the Text property of your TextBlock to this value. Of course, you cannot do this with txtFont.Text = ..., since this only works for strings. For other types of objects, you need to set the DependencyProperty directly:
txtFont.SetValue(TextBlock.TextProperty, myFlowDocument)
Here is how we are setting the look of a textblock by assigning a style on-the-fly.
// Set Weight (Property setting is a string like "Bold")
FontWeight thisWeight = (FontWeight)new FontWeightConverter().ConvertFromString(Properties.Settings.Default.DealerMessageFontWeightValue);
// Set Color (Property setting is a string like "Red" or "Black")
SolidColorBrush thisColor = (SolidColorBrush)new BrushConverter().ConvertFromString(Properties.Settings.Default.DealerMessageFontColorValue);
// Set the style for the dealer message
// Font Family Property setting is a string like "Arial"
// Font Size Property setting is an int like 12, a double would also work
Style newStyle = new Style
{
TargetType = typeof(TextBlock),
Setters = {
new Setter
{
Property = Control.FontFamilyProperty,
Value = new FontFamily(Properties.Settings.Default.DealerMessageFontValue)
},
new Setter
{
Property = Control.FontSizeProperty,
Value = Properties.Settings.Default.DealerMessageFontSizeValue
},
new Setter
{
Property = Control.FontWeightProperty,
Value = thisWeight
},
new Setter
{
Property = Control.ForegroundProperty,
Value = thisColor
}
}
};
textBlock_DealerMessage.Style = newStyle;
You can eliminate the style section and set properties directly, but we like keeping things bundled in the style to help us organize the look throughout the project.
textBlock_DealerMessage.FontWeight = thisWeight;
HTH.

Categories

Resources