WPF|Dynamically add hyperlink to RTB text - c#

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.

Related

Search a word in rich edit control of devexpress

I want to search a word in rich edit control. I will write a word in a text box and then click on a button named search button, and then the searched word will be highlighted in the rich edit control.
How can I solve this problem?
In rich text box we use RichTextBox.TextLength, but rich edit control doesn't support this.
private void button2_Click(object sender, EventArgs e) //Search button
{
int index = 0;
while(index <= richEditControl1.Text.LastIndexOf(textBox1.Text))
{
richEditControl1.Find(textBox1.Text, index, richEditControl1.TextLength, RichTextBoxFinds.None);
richEditControl1.SelectionBackColor = Color.IndianRed;
index = richEditControl1.Text.IndexOf(textBox1.Text, index) + 1;
}
}
Try with StartSearch method. Something like this.
private void SearchRTF(string mytext) {
var result = myRichEditControl.Document.StartSearch(mytext);
if (result.FindNext()) {
var section = myRichEditControl.Document.BeginUpdateCharacters(result.CurrentResult);
section.ForeColor = System.Drawing.Color.White;
section.BackColor = System.Drawing.Color.Blue;
myRichEditControl.Document.EndUpdateCharacters(section);
}
}

C# WPF RichTextBox Scroll to text?

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

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);
}

adding content to a button click in wpf

Why cant I do this in wpf?
button1Click.Content = "Hover over me";
or
ToolTip t = new ToolTip();
t.Content = "Something helpful";
button1Click.Tooltip = t;
I populate my widow with populate buttons on initialization I then have a foreach loop that adds buttons like so:
foreach (var routedEventHandler in new RoutedEventHandler[] { button1Click, button2Click, button3_Click })`
Now in this area I apply styles to the buttons all in one go like so:
public void populateButtons()
{
double xPos;
double yPos;
Random ranNum = new Random();
foreach (var routedEventHandler in new RoutedEventHandler[] { button1Click, button2Click, button3_Click })
{
Button foo = new Button();
Style buttonStyle = Window.Resources["CurvedButton"] as Style;
int sizeValue = 100;
foo.Width = sizeValue;
foo.Height = sizeValue;
xPos = ranNum.Next(200);
yPos = ranNum.Next(250);
foo.HorizontalAlignment = HorizontalAlignment.Left;
foo.VerticalAlignment = VerticalAlignment.Top;
foo.Margin = new Thickness(xPos, yPos, 0, 0);
foo.Style = buttonStyle;
foo.Click += routedEventHandler;
LayoutRoot.Children.Add(foo);
}
}
}
}
But when I try this:
private void button3_Click(object sender, RoutedEventArgs e)
{
((Button)sender).ToolTip = t;
}
It only activates when a button is pressed? (Thanks #H.B)
However when I paste the tooltip code in my populate buttons:
Random ranNum = new Random();
foreach (var routedEventHandler in new RoutedEventHandler[] { button1Click, button2Click, button3_Click })
{
Button foo = new Button();
ToolTip t = new ToolTip();
t.Content = "Something helpful";
foo.ToolTip = t;
It works? But the problem is that doing it this way sets all buttons with the same tooltip and or button content! which I dont want, but I cant find a way around it?
So to summarize I can either set all buttons with the same tooltip message or button content within "populateButtons()" or I can only set tooltips and button content when the button has been pressed.
Is there no method possible that can add content to a named button?
Like my initial attempt:
button1Click.Content = "Home Button";
or
button1Click.ToolTip = "Hover over me";
Why on earth cant you set content and tooltips for specific buttons on initialization?
If you want to go this route then you can add a handler for Loaded event:
foo.Click += routedEventHandler;
foo.Loaded += routedEventHandler;
And then you have something like:
void button2Click(object sender, RoutedEventArgs e)
{
if (e.RoutedEvent == FrameworkElement.LoadedEvent)
{
ToolTip t = new ToolTip();
t.Content = "Something helpful";
((Button)sender).ToolTip = t;
return;
}
//Logic for handling button clicks goes here
MessageBox.Show("action 2");
}
You are not assigning the tooltip in the handler, so how should anything happen?
((Button)sender).ToolTip = t;
If I understand correctly, you want to have different "types" of buttons, each one with a different Click handler and a different Tooltip.
If that's the case, You could create different classes deriving from Button (e.g. HelpfulButton, UnhelpfulButton... choose good names please :) ) and in their constructor assign the handler and tooltip.
Then, in the main code, you could loop through the different classes and add instances of them directly to the main canvas.
Another possible option is to create different "template" buttons using commands and copy the properties from them instead of subclassing Button. Something like this:
Button helpfulTemplate = new Button { ToolTip = "blah" };
helpfulTemplate.Command = HelpfulCommand;
Button unhelpfulTemplate = new Button { ToolTip = "bloh" };
unhelpfulTemplate.Command = UnhelpfulCommand;
foreach(var template in new Button[] {helpfulTemplate, unhelpfulTemplate})
{
var newCopy = new Button();
//etc.
newCopy.ToolTip = template.ToolTip;
newCopy.Command = template.Command;
}

Categories

Resources