As you can tell from the title, Im having a bit of issue regarding assigning and removing format styles to and from selected text in the RichTexBox control.
I know how to make text individually Bold/Italic/Underline, but not a combination of these. I know of ways that can achieve this character by character, but this would seem time-consuming on the interface. If it can be effortlessly done in Wordpad, Im sure it can be achieved here!
Is there no such method or such that exists that can allow me to "add" or "remove" a style from RichTextBox.SelectedFont?
Unless I am completely misunderstanding the question
// Get the current text selection or to text entered after the insertion point.
// Build new font based on the selection font, make it both Bold and Underline
// Apply new font to currently selected text (or for new text at insertion point
Font currFont = richTextBox.SelectionFont;
Font boldUnderFont = new Font(currFont, FontStyle.Bold | FontStyle.Underline);
richTextBox.SelectionFont = boldUnderFont;
I had to do same think as you had to do. I see it is an old post. However, for those that might encounter same issue. You can not apply a font style, font family, ..., to a string unless you iterate character by character and thus you can get SelectionFont.
This is the method that can help you:
/// <summary>
/// Changes a font from originalFont appending other properties
/// </summary>
/// <param name="originalFont">Original font of text
/// <param name="familyName">Target family name
/// <param name="emSize">Target text Size
/// <param name="fontStyle">Target font style
/// <param name="enableFontStyle">true when enable false when disable
/// <returns>A new font with all provided properties added/removed to original font</returns>
private Font RenderFont(Font originalFont, string familyName, float? emSize, FontStyle? fontStyle, bool? enableFontStyle)
{
if (fontStyle.HasValue && fontStyle != FontStyle.Regular && fontStyle != FontStyle.Bold && fontStyle != FontStyle.Italic && fontStyle != FontStyle.Underline)
throw new System.InvalidProgramException("Invalid style parameter to ChangeFontStyleForSelectedText");
Font newFont;
FontStyle? newStyle = null;
if (fontStyle.HasValue)
{
if (fontStyle.HasValue && fontStyle == FontStyle.Regular)
newStyle = fontStyle.Value;
else if (originalFont != null && enableFontStyle.HasValue && enableFontStyle.Value)
newStyle = originalFont.Style | fontStyle.Value;
else
newStyle = originalFont.Style & ~fontStyle.Value;
}
newFont = new Font(!string.IsNullOrEmpty(familyName) ? familyName : originalFont.FontFamily.Name,
emSize.HasValue ? emSize.Value : originalFont.Size,
newStyle.HasValue ? newStyle.Value : originalFont.Style);
return newFont;
}
For more details about how to make a custom richtexBox control you can go to http://how-to-code-net.blogspot.ro/2014/01/how-to-make-custom-richtextbox-control.html
Related
In the Fluent Ribbon Control Suite, is there a way to make the contextual tab groups show up first instead of last? I was using an older build and had a contextual tab group for the first three tab items, and two more with no group. Downloaded and built the newest source; the tabs in the group are now on the right end. I want them to show in the same order as I have them specified in the xaml. I don't see any obvious properties that would allow me to specify the order.
Since no one had an answer to this, and I just got a Tumbleweed badge for it :), I decided to post my solution, which was to modify the Fluent Ribbon Control Suite code. I modified ArrangeOverride in the RibbonTabsContainer class. This caused the Grouped tabs to be rendered before the ones not in a group:
/// <summary>
/// Positions child elements and determines
/// a size for the control
/// </summary>
/// <param name="finalSize">The final area within the parent
/// that this element should use to arrange
/// itself and its children</param>
/// <returns>The actual size used</returns>
protected override Size ArrangeOverride(Size finalSize)
{
var finalRect = new Rect(finalSize)
{
X = -this.HorizontalOffset
};
var orderedChildren = this.InternalChildren.OfType<RibbonTabItem>()
.OrderByDescending(x => x.Group != null); // <==== originally .OrderBy
foreach (var item in orderedChildren)
{
finalRect.Width = item.DesiredSize.Width;
finalRect.Height = Math.Max(finalSize.Height, item.DesiredSize.Height);
item.Arrange(finalRect);
finalRect.X += item.DesiredSize.Width;
}
var ribbonTabItemsWithGroups = this.InternalChildren.OfType<RibbonTabItem>()
.Where(item => item.Group != null);
var ribbonTitleBar = ribbonTabItemsWithGroups.Select(ribbonTabItemsWithGroup => ribbonTabItemsWithGroup.Group.Parent)
.OfType<RibbonTitleBar>()
.FirstOrDefault();
if (ribbonTitleBar != null)
{
ribbonTitleBar.InvalidateMeasure();
}
return finalSize;
}
I'm looking at ways to resolve an issue with a Winforms application, which uses a ComboBox control. Specifically, the ComboBox (Style=DropDownList) is bound to a datasource and, as the user navigates through some other data, the "Text" property of the ComboBox property is set - and the user can select some other value.
The trouble starts when the value I set the "Text" property to is not in the list of available items. It seems that nothing happens. Take the following simple example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
myComboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
//myComboBox1.Items.AddRange(new[] { "One", "Two", "Three" });
List<KeyValuePair<Int32, String>> values = new List<KeyValuePair<Int32, String>>();
values.Add(new KeyValuePair<Int32, String>(1, "One"));
values.Add(new KeyValuePair<Int32, String>(2, "Two"));
values.Add(new KeyValuePair<Int32, String>(3, "Three"));
myComboBox1.DataSource = values;
myComboBox1.ValueMember = "Key";
myComboBox1.DisplayMember = "Value";
button1.Click += (s, e) => { myComboBox1.Text = "Four"; };
button2.Click += (s, e) => { myComboBox1.SelectedIndex -= 1; };
}
}
public class MyComboBox : System.Windows.Forms.ComboBox
{
public override string Text
{
get { return base.Text; }
set { MessageBox.Show(value); base.Text = value; }
}
}
This technique is used throughout a large application, so when it was noticed that (in the example above) setting the "Text" to "Four" does nothing, I thought that maybe I could trap this and throw an exception. In reality, the application is peppered with code like this:
if (myDataRow.IsBlahNull())
myComboBox1.Text = "";
else
myComboBox1.Text = myDataRow.Blah;
Now, while I appreciate that setting "SelectedIndex = -1" would be better for the "IsNull" case, the fact remains that myDataRow.Blah may not be a valid value. Also, the application is written (and live) so the fewer changes the better.
So, my immediate thought was "let's override the Text property setter and check that the value is in the list". That, it turns out, is nothing like as simple as it would seem. The problem being that the "Text" property is set to all kinds of things, in all kinds of scenarios. For example, it's set when the DataSource property is assigned, or when the SelectedIndex is set to -1. Also, it's set to the string representation of the selected item - so if you happen to have a ComboBox control that's bound to a List of KeyValue pairs, you get the "Text" property set to something like "[Key,Value]". If it's bound to a DataTable/DataView, you get the string representation of the DataRow, and that gets even harder to detect.
It's at this point I thought that there might be another way to achieve the desired result (which is to detect the setting of the Text property to some invalid value - which does nothing).
Any ideas ?
Upon reflection, is this a reasonable work-around ?
/// <summary>
/// Gets or sets the text associated with this control.
/// </summary>
public override string Text
{
get { return base.Text; }
set
{
base.Text = value;
if ((value != null) && (base.Text != value))
if (value == "")
this.SelectedIndex = -1;
else
throw new ArgumentException(String.Format("Cannot set Text property of {0} to \"{1}\".", this.Name, value));
}
}
I am trying to build a USerControl that contains a GMapControl. When I place the GMapControl directly on the Form, then it works as expected. If I however place the GMapControl on a UserControl, and then add that UserControl to the Form, I get errors.
For example:
My UserControl, Map.cs:
public Map()
{
InitializeComponent();
gMapControl1.MapProvider = GMapProviders.OpenStreetMap;
gMapControl1.Position = new PointLatLng(54.6961334816182, 25.2985095977783);
gMapControl1.MinZoom = 1;
gMapControl1.MaxZoom = 24;
gMapControl1.Zoom = 9;
top = new GMapOverlay("1");
objects = new GMapOverlay("objects");
routes = new GMapOverlay("routes");
polygons = new GMapOverlay("polygons");
gMapControl1.Overlays.Add(routes);
gMapControl1.Overlays.Add(polygons);
gMapControl1.Overlays.Add(objects);
gMapControl1.Overlays.Add(top);
gMapControl1.OnMarkerClick += new MarkerClick(gMapControl1_OnMarkerClick);
gMapControl1.OnPolygonClick += new PolygonClick(gMapControl1_OnPolygonClick);
}
Then I add this UserControl to my Form by dragging it on there. Then I get an Exception:
Failed to create component 'Map'. The error message follows:
'System.MissingMethodException: Method not found: 'Void
GMap.NET.WindowsForms.GMapControl.set_MapProvider(GMap.NET,
MapProviders.GMapProvider)'. at OpenStreetMapTest.Map..ctor()'
If I have the same code that I have in the UserControl Map inside a Form, then no errors. Also, the set_MapProvider exists and works if I don't put the GMapControl inside a UserControl.
Any ideas?
Decompile the code and see what the Map construtor is doing. Maybe it's locating some method by reflection. Can't think why else you'd get a MissingMethodException dependong on where the control is sitting.
On DesignMode suggestion, that property just flat out doesn't work for nested user controls which is really frustrating. However, you can use the following work around (this property would be in a UserControlBase class from which you would inherit)
Simply check IsDesignerHosted instead of IsDesignMode.
/// <summary>
/// Indicates if the code is being run in the context of the designer
/// </summary>
/// <remarks>
/// <see cref="Component.DesignMode"/> always returns false for nested controls. This is one
/// of the suggested work arounds here: http://stackoverflow.com/questions/34664/designmode-with-controls
/// </remarks>
public bool IsDesignerHosted
{
get
{
Control ctrl = this;
while (ctrl != null)
{
if ((ctrl.Site != null) && ctrl.Site.DesignMode)
return true;
ctrl = ctrl.Parent;
}
return false;
}
}
you should wrap everything inside the if ( !DesignMode )
eg.
Map()
{
InitializeComponent();
if ( !DesignMode )
{
gMapControl1.MapProvider = GMapProviders.OpenStreetMap;
gMapControl1.Position = new PointLatLng(54.6961334816182, 25.2985095977783);
gMapControl1.MinZoom = 1;
gMapControl1.MaxZoom = 24;
gMapControl1.Zoom = 9;
top = new GMapOverlay("1");
objects = new GMapOverlay("objects");
routes = new GMapOverlay("routes");
polygons = new GMapOverlay("polygons");
gMapControl1.Overlays.Add(routes);
gMapControl1.Overlays.Add(polygons);
gMapControl1.Overlays.Add(objects);
gMapControl1.Overlays.Add(top);
gMapControl1.OnMarkerClick += new MarkerClick(gMapControl1_OnMarkerClick);
gMapControl1.OnPolygonClick += new PolygonClick(gMapControl1_OnPolygonClick);
}
}
Ok, I know that the new versions of windows do not use the insert key by default and you have to program for it. I want to be able to type in my text box and override the content that is in it just like in old windows when you could activate the insert key. This is just for my WPF 4, VB.net Application.
Updated Information:
That what I meant: I need to mimic old terminals. I need to activate the overwrite mode programmatically for all the controls. The same affect as the 'Insert' key on the keyboard. Only that key does not work in a WPF environment.
Example I am entering the word world over a text box that says 'Hello!':
Textbox Started as: [Hello!]
The Textbox is now [World!]
You will note that the one character exclamation mark stayed because world is not enough characters to replace the '!'.
Try this out (use this control instead of vanilla TextBoxes):
public class InsertModeTextBox : TextBox
{
public InsertModeTextBox()
{
InitializeComponent();
}
protected override void OnTextInput(TextCompositionEventArgs e)
{
var txt = e.Text;
var len = txt.Length;
var pos = CaretIndex;
var builder = new StringBuilder();
if (pos > 0) builder.Append(Text.Substring(0, pos)); // text before caret
builder.Append(txt); // new text
if (Text.Length > pos + len) builder.Append(Text.Substring(pos + len)); // text after overwrite
Text = builder.ToString();
CaretIndex = pos + len;
e.Handled = true;
}
}
In WPF 4 pressing Insert key when textbox has focus activates overwrite mode. Do you mean changing between Insert and Overwrite modes for all textboxes on a window at once?
When a user clicks in certain places in my control, I want to change the color of some rows and columns in my grid, then fade it back to the normal color, within say 500ms or so. I haven't decided whether to use Winforms or WPF yet, so advice in either of those technologies would work. Thank you.
Edit: I understand I could do this by just calling Paint in a loop within the click event, properly setting the drawing parameters. However I believe that would block the UI, and I would like to be more responsive than that.
WPF has very good support for animations. Animations are supported from both xaml and code behind, so you should be able to achieve any look that you are going for.
The MSDN Animation Overview for WPF looks to have a lot of good information for getting you started.
Here is one way you could handle the fade:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsApplication1
{
public class FadeForm : Form
{
private Timer fadeTimer;
private Panel fadePanel;
private Button fadeButton;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose( bool disposing )
{
if ( disposing && ( components != null ) )
{
components.Dispose();
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.fadePanel = new System.Windows.Forms.Panel();
this.fadeButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// fadePanel
//
this.fadePanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.fadePanel.Location = new System.Drawing.Point( 4, 8 );
this.fadePanel.Name = "fadePanel";
this.fadePanel.Size = new System.Drawing.Size( 276, 104 );
this.fadePanel.TabIndex = 0;
//
// fadeButton
//
this.fadeButton.Location = new System.Drawing.Point( 104, 116 );
this.fadeButton.Name = "fadeButton";
this.fadeButton.Size = new System.Drawing.Size( 75, 23 );
this.fadeButton.TabIndex = 1;
this.fadeButton.Text = "Fade";
this.fadeButton.UseVisualStyleBackColor = true;
this.fadeButton.Click += new System.EventHandler( this.HandleFadeButtonClick );
//
// FadeForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F );
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size( 284, 142 );
this.Controls.Add( this.fadeButton );
this.Controls.Add( this.fadePanel );
this.Name = "FadeForm";
this.Text = "Fade Form";
this.ResumeLayout( false );
}
#endregion
public FadeForm()
{
InitializeComponent();
this.fadeTimer = new Timer();
}
private void HandleFadeButtonClick( object sender, EventArgs e )
{
this.fadeTimer.Tick += new EventHandler( HandleFadeTimerTick );
this.fadePanel.BackColor = Color.Red;
this.fadeTimer.Interval = 100;
this.fadeTimer.Start();
}
void HandleFadeTimerTick( object sender, EventArgs e )
{
Color panelColor = this.fadePanel.BackColor;
if ( panelColor.A > 0 )
{
this.fadePanel.BackColor =
Color.FromArgb(
Math.Max( panelColor.A - 20, 0 ),
panelColor.R, panelColor.G, panelColor.B );
}
else
{
this.fadeTimer.Stop();
}
}
}
}
Unfortunately, this approach doesn't seem to work with rows in a DataGridView. I don't know the reason, but the color doesn't show at all if the alpha component of the color isn't 255. If you can find a way around that, this code might help.
At its simplest, a fade effect like this just requires a timer of some sort that gradates the color back towards normal with each tick. The faster the time, the more discrete colors you will display from start to finish, and the smoother the overall effect will be (WPF may have something built-in to do this).
You definitely do not want to repaint in a loop. As you pointed out this will block the UI, and also you would not be able to control how long the loop takes (different machines will render the same number of steps from highlight color to normal in different lengths of time).