C# WPF RichTextBox Scroll to text? - c#

I'm working on alittle writing game and I encountered a problem. I have a richtextbox which contains one paragraph with alot of runs in it, and I want it to scroll to some run i have. I have a List object which contains all the inlines in the RTB, and the Select() Method doesn't work for some reason, maybe because it's a ready-only rtb. Any ideas for a way to scroll to selected word?
My Code:
private bool isKey = false;
private Paragraph p;
private List<Inline> inlineList;
private int inlineIndex = 0, wpm = 0, wordIndex = 0, lineIndex = 0;
private string[] words;
public MainWindow()
{
InitializeComponent();
p = new Paragraph();
foreach (string s in words)
{
p.Inlines.Add(s);
p.Inlines.Add(" ");
}
WordBox.Document.Blocks.Clear();
WordBox.Document.Blocks.Add(p);
inlineList = p.Inlines.ToList();
inlineList[0].Background = Brushes.LightGray;
this.Activate();
InputBox.Focus();
}
//The Method I want to put the scrolling feature in:
private void MoveWord()
{
if (inlineIndex + 2 < inlineList.Count)
{
inlineList[inlineIndex].Background = Brushes.Transparent;
inlineIndex += 2;
inlineList[inlineIndex].Background = Brushes.LightGray;
WordBox.Selection.Select(inlineList[inlineIndex].ContentStart, inlineList[inlineIndex].ContentEnd);
}
else
MessageBox.Show(wpm.ToString());
}
For Example:
the rtb contains:
Hey Hello what's up
word schnitzel hey
And I want it to scroll to the word "hey".
I've tried to use Select() method, which didn't work...

Create runs and add runs (not inlines)
Save a reference to the runs (e.g. a List)
And then just call Runs[x].BringIntoView()
Have not tested on RTB but I have done this with FlowDocument and FlowDocumentViewer
BringIntoView

Related

WPF|Dynamically add hyperlink to RTB text

I wrote some code which dynamically coloring "key word" in text writen in RTB WPF control. I want to change coloring in hyperlinks such like wikipedia have. But when i used that code:
new struct Tag
{
public TextPointer StartPosition;
public TextPointer EndPosition;
public string Word;
}
List<Tag> m_tags = new List<Tag>();//list with key words which may transform to hyperlinks
//TextInput is RTB
private void TextFormating()
{
TextInput.TextChanged -= this.TextChangedEventHandler;
TextInput.IsEnabled = true;
for(int i=0; i<m_tags.Count;i++)
{
Hyperlink link = new Hyperlink(m_tags[i].StartPosition,m_tags[i].EndPosition);
link.IsEnabled = true;
link.NavigateUri = new Uri(#"www.google.com");
link.RequestNavigate += new RequestNavigateEventHandler(link_RequestNavigate);
}
m_tags.Clear();
TextInput.TextChanged += this.TextChangedEventHandler;
}
Line where i create Hyperlink shows Exception "start is not expected after end".
Thanks for any idea.

Readonly richtextbox changing color of keyword C#

I have a rich text box that i am using to display an example of the Hello World program and want the keywords such as 'using' 'namespace' 'class' 'static' 'void' 'string' to display blue.
I have got 'using' to display blue but only when the user starts to type or types 'using'
I want the richtextbox to be read only not allowing an user input into it
Here is my code:
private void rtb_TextChanged(object sender, EventArgs e)
{
string find = "using";
if (rtb.Text.Contains(find))
{
var matchString = Regex.Escape(find);
foreach (Match match in Regex.Matches(rtb.Text, matchString))
{
rtb.Select(match.Index, find.Length);
rtb.SelectionColor = Color.Blue;
rtb.Select(rtb.TextLength, 0);
rtb.SelectionColor = rtb.ForeColor;
};
}
}
I am having trouble figuring out how to do it for readonly rtb.
How could i edit my code to display the blue text on initialize in a readonly rtb
Thanks for your help
There's no need to subscribe to the TextChanged event.
Place your code in a separate method:
private void ApplySyntaxHighlite()
{
string find = "using";
if (richTextBox1.Text.Contains(find))
{
var matchString = Regex.Escape(find);
foreach (Match match in Regex.Matches(richTextBox1.Text, matchString))
{
richTextBox1.Select(match.Index, find.Length);
richTextBox1.SelectionColor = Color.Blue;
richTextBox1.Select(richTextBox1.TextLength, 0);
richTextBox1.SelectionColor = richTextBox1.ForeColor;
};
}
}
And call it after you set the text in the RichTextBox:
richTextBox1.Text =
"using System;\r\nusing System.IO;\r\n\r\nConsole.WriteLine(\"Hello world.\");";
ApplySyntaxHighlite();

C# Drag and Drop labels within FlowLayoutPanels

I have small problem. I want make program where I can drag generated labels between multiple FlowLayoutPanels. But last few days I have tried to make drag and drop working. I tried many tutorials, examples etc. but it is always something bit diferent and I am not able extract only basic code.
It is similar to this program but it is in Visual Basic and I need it in C#. I know it is maybe very simple, but I am newbie.
Thank you for help.
Real Drag&Drop ist most useful between applications and maybe also between Forms.
Assuming you want to drag Labels between FLPs on the same Form, the code below should get you going..
It takes two FlowLayoutPanels called FLP1 and FLP2 and starts by initializing them with a few Labels.
Note the three mouse events I add to each Label to emulate a Drag&Drop action!
private void Form1_Load(object sender, EventArgs e)
{
// create a few Label with varying Colors for testing..
fillFLP(FLP1, 88);
fillFLP(FLP2, 111);
}
void fillFLP(FlowLayoutPanel FLP, int cc)
{
for (int i = 0; i < 24; i++)
{
Label l = new Label();
// the next 3 lines optional and only are there for testing!
l.AutoSize = false;
l.Text = FLP.Name + " " + i.ToString("00");
l.BackColor = Color.FromArgb(255, cc * 2 - i, 255 - 5 * i, cc + 5 * i);
// add controls and set mouse events:
FLP.Controls.Add(l);
l.MouseDown += l_MouseDown;
l.MouseMove += l_MouseMove;
l.MouseUp += l_MouseUp;
}
}
// the currently moved Label:
Label mvLabel = null;
void l_MouseDown(object sender, MouseEventArgs e)
{
// keep reference
mvLabel = (Label)sender;
}
void l_MouseMove(object sender, MouseEventArgs e)
{
// if we are dragging a label:
if (mvLabel != null)
{
// mouse pos in window coords
Point mvPoint = this.PointToClient(Control.MousePosition);
// the label is still in the FLP, so we start the drg action:
if (mvLabel.Parent != this)
{
mvLabel.Parent = this;
mvLabel.Location = mvPoint;
mvLabel.BringToFront();
}
else
{
// we are already in the form, so we just move
mvLabel.Location = mvPoint;
}
}
}
void l_MouseUp(object sender, MouseEventArgs e)
{
// are we over a FLP? and if so which?
Point MP = Control.MousePosition;
FlowLayoutPanel FLP = null;
Point mLoc1 = FLP1.PointToClient(MP);
Point mLoc2 = FLP2.PointToClient(MP);
if (FLP1.ClientRectangle.Contains(mLoc1)) FLP = FLP1;
else if (FLP2.ClientRectangle.Contains(mLoc2)) FLP = FLP2;
else return; // no! nothing we can do..
// yes, now find out if we are over a label..
// ..or over an empty area
mvLabel.SendToBack();
Control cc = FLP.GetChildAtPoint(FLP.PointToClient(MP));
// if we are over the FLP we can insert at the beginning or the end:
// int mvIndex = 0; // to the beginning
int mvIndex = FLP.Controls.Count; // to the end
// we are over a Label, so we insert before it:
if (cc != null) mvIndex = FLP.Controls.IndexOf(cc);
// move the Label into the FLP
FLP.Controls.Add(mvLabel);
// move it to the right position:
FLP.Controls.SetChildIndex(mvLabel, mvIndex);
// let go of the reference
mvLabel = null;
}
This lets you drag and drop Lables to and fro between two FLPs and also within the FLPs by dropping onto Labels.
Note that you will need a few extra lines if you want to allow dropping between Labels and still position there..

Get rid of blinking when adding controls dynamically to FlowLayoutpanel, triggered by timer

I'm trying to make a custom control, to show some data from a SQL source. The data should change in a method, which is triggered by a Timer control.
Let say, if I append all my needed data in stringbuffer and then I show this in long label is working. Every time label is repainted, there is no blinking.
But, if I want make more fancy look, I found only way to put controls in FLowLayoutPanel and build whole structure. Ok, it works, but every time the controls are drawn, I need to dispose them. If not, controls being added to infinity, and buffer overload.
But If I dispose() or clear() them, there is blinking every time controls are redrawn.
Is there a way to get rid of this blinking? Or maybe some other way to do my work?
My code:
void timer_Tick(object sender, EventArgs e)
{
try
{
GetMapData();
}
catch (Exception ex)
{
}
}
private void GetMapData()
{
DataSet ds = MapStatistics.GetMapData(top, bottom, left, right, idUnit, idCustomerTmp);
DataTable activDriversForZones = ds.Tables["ActivDriversForZone"];
DataTable zones zones = ds.Tables["Zones"];
if (zones != null || zones.Rows.Count > 0)
{
ClearflpPanel(flpTest2);
zonesDriverCount = 0;
foreach (DataRow rowZones in zones.Rows)
{
string idZone = Convert.ToString(rowZones["id_zone"]);
string title = Convert.ToString(rowZones["title"]);
StringBuilder zoneDriver = new StringBuilder();
Label labelRowZone = new Label();
labelRowZone.Width = 400;
labelRowZone.AutoSize = true;
labelRowZone.Font = new System.Drawing.Font("Arial", 10, FontStyle.Bold);
labelRowZone.Text = (title + ": ");
flpTest2.Controls.Add(labelRowZone);
Label labelRowDriver = new Label();
foreach (DataRow rowDriver in activDriversForZones.Rows)
{
string idUnit = Convert.ToString(rowDriver["id_unit"]);
string imsi = Convert.ToString(rowDriver["imsi"]);
string zoneIn = Convert.ToString(rowDriver["zone_in"]);
if (idZone == zoneIn)
{
zonesDriverCount++;
zoneDriver.Append(imsi + "/" + idUnit + ", ");
labelRowDriver.Text = (zoneDriver.ToString());
}
flpTest2.Controls.Add(labelRowDriver);
}
}
}
}
public void ClearflpPanel(FlowLayoutPanel flp)
{
zonesDriverCount = 0;
List<Control> listControls = flp.Controls.Cast<Control>().ToList();
foreach (Control control in listControls)
{
flpTest2.Controls.Clear();
//flpTest2.Dispose();
}
}
Create a custom flowLayoutPanel class and add this in its constructor
public class CustomFLP: FlowLayoutPanel
{
public CustomFLP() : base()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.UpdateStyles();
}
}
Then do everything the same way you are doing now except you create your flowlayout panel with CustomFLP instead of FlowLayoutPanel.
This adds a double buffer to your control, might not work with a lot of updates.
I find combining Vajura's method and wrap the update with SuspendLayout() / ResumeLayout() will completely remove the flickering.
// Declaration
CustomFLP m_doubleBufferFlowLayoutPanel;
void UpdatePanel()
{
m_doubleBufferFlowLayoutPanel.SuspendLayout();
// update the flow layout panel here
...
m_doubleBufferFlowLayoutPanel.ResumeLayout();
}

Can't count words from richtextbox to label?

I'm not sure what's wrong here, but i'm trying to count words in a richtext box, and display that with a label.
I put a richtextbox in a tab control so I can have a tabbed text box. Which seems to make this a lot harder then it should
also this isn't the whole program, I took the parts relating to the richtextbox and word counter
Any help is appreciated :)
public RichTab()
{
InitializeComponent();
TabPage tp = new TabPage("Document");
RichTextBox rtb = new RichTextBox();
rtb.Dock = DockStyle.Fill;
tp.Controls.Add(rtb);
tabControl1.TabPages.Add(tp);
WordCount();
}
public RichTextBox RTTB()
{
RichTextBox rtb = null;
TabPage tp = tabControl1.SelectedTab;
if (tp != null)
{
rtb = tp.Controls[0] as RichTextBox;
}
return rtb;
}
private void WordCount()
{
MatchCollection wordColl = Regex.Matches(RTTB().Text, #"[\W]+");
label2.Text = wordColl.Count.ToString();
}
I would probably just wire up the TextChanged event of the RichTextBox, and count the words there:
rtb.TextChanged += rtb_TextChanged;
Then count the words (using Giorgio Minardi's regex):
private void rtb_TextChanged(object sender, EventArgs e) {
label2.Text = Regex.Matches(((RichTextBox)sender).Text, #"[\S]+").Count.ToString();
}
What's the actual issue ?
Here's a simple routine to count words:
[Test]
public void CountWords()
{
const string sample = "How you doing today ?";
MatchCollection collection = Regex.Matches(sample, #"[\S]+");
var numberOfWords = collection.Count;
//numberOfWords is 5
Assert.IsTrue(numberOfWords == 5);
}

Categories

Resources