C# WPF Text with links - c#

I just found myself a new challenge:
Make a Word Processor that is in handling more like the web than plain text.
Designing a nice framework for this is what i cant wait to start with, but i do need to know what the possibilities are at the GUI side (it will probably have loads of GUI challenges).
So the basic thing that I need some sort of Control where I can make parts of my text clickable / mouse-over-able.
I'm kinda new to WPF and not sure how to do this.
Has anybody an idea how to make this?
Are there examples?
Are there already controls for this?
Thanks in advance
EDIT:
I found out some way to do it with a richtextbox:
// Create a FlowDocument to contain content for the RichTextBox.
FlowDocument myFlowDoc = new FlowDocument();
// Add paragraphs to the FlowDocument.
Hyperlink myLink = new Hyperlink();
myLink.Inlines.Add("hyperlink");
myLink.NavigateUri = new Uri("http://www.stackoverflow.com");
// Create a paragraph and add the Run and hyperlink to it.
Paragraph myParagraph = new Paragraph();
myParagraph.Inlines.Add("check this link out: ");
myParagraph.Inlines.Add(myLink);
myFlowDoc.Blocks.Add(myParagraph);
// Add initial content to the RichTextBox.
richTextBox1.Document = myFlowDoc;
I now get a nice hyperlink in my textbox... except when i click it, nothing happens.
what am i missing here?

You can use the Hyperlink class. It's a FrameworkContentElement, so you can use it in a TextBlock or FlowDocument or anywhere else you can embed content.
<TextBlock>
<Run>Text</Run>
<Hyperlink NavigateUri="http://stackoverflow.com">with</Hyperlink>
<Run>some</Run>
<Hyperlink NavigateUri="http://google.com">hyperlinks</Hyperlink>
</TextBlock>
You may want to look at using a RichTextBox as part of your editor. This will host a FlowDocument, which can contain content such as Hyperlinks.
Update: There are two ways to handle clicks on the Hyperlink. One is to handle the RequestNavigate event. It is a Routed Event, so you can either attach a handler to the Hyperlink itself or you can attach one to an element higher in the tree such as the Window or the RichTextBox:
// On a specific Hyperlink
myLink.RequestNavigate +=
new RequestNavigateEventHandler(RequestNavigateHandler);
// To handle all Hyperlinks in the RichTextBox
richTextBox1.AddHandler(Hyperlink.RequestNavigateEvent,
new RequestNavigateEventHandler(RequestNavigateHandler));
The other way is to use commanding by setting the Command property on the Hyperlink to an ICommand implementation. The Executed method on the ICommand will be called when the Hyperlink is clicked.
If you want to launch a browser in the handler, you can pass the URI to Process.Start:
private void RequestNavigateHandler(object sender, RequestNavigateEventArgs e)
{
Process.Start(e.Uri.ToString());
}

Note you also need to set the following properties on your RichTextBox or the hyperlinks will be disabled and won't fire off events. Without IsReadOnly you need to Ctrl-click the hyperlinks, with IsReadOnly they fire with a regular left-click.
<RichTextBox
IsDocumentEnabled="True"
IsReadOnly="True">

The simplest way is to handle RequestNavigate event like this:
...
myLink.RequestNavigate += HandleRequestNavigate;
...
private void HandleRequestNavigate(object sender, RoutedEventArgs e)
{
var link = (Hyperlink)sender;
var uri = link.NavigateUri.ToString();
Process.Start(uri);
e.Handled = true;
}
There are some issues with starting a default browser by passing url to the Process.Start and you might want to google for a better way to implement the handler.

Related

How do I prevent RichTextBox from jumping to the top of the document when links are clicked?

As part of my GUI in C# (.Net 5.0) I'm using the RichTextBox control (part of System.Windows.Forms) to display text and clickable links. My problem is when I click any links included without the form first having focus the act of clicking a link also focuses the textbox which automatically places the caret at the start of the text, this has the effect of making the textbox jump (or scroll) to the very top of document, losing one's position.
For my particular problem, the RichTextBox classes are assigned to TabPages within a TabControl- and all three of these components are created in response to user interaction (I understood the creation of these at runtime might limit the types of event handling available to me).
I've defined the RichTextBox control with multiline and both horizontal and vertical scrollbars, and to enable clickable links I'm using the DetectUrls option. Here is the full list of properties being used.
var control = new RichTextBox();
control.DetectUrls = true;
control.Dock = DockStyle.Fill;
control.Multiline = true;
control.ReadOnly = true;
control.WordWrap = false;
control.Text = myContent; // large content filling multiple screens
control.ScrollBars = RichTextBoxScrollBars.Both;
control.LinkClicked += new LinkClickedEventHandler(RichTextBoxLinkClicked);
I've included the LinkClicked because I want to provide some interaction for the user, but whether this handler is assigned or not doesn't seem to influence the problem.
Edit1 I came up with a solution that works to some extent; it prevents the scrolling by placing the caret at the beginning of the link (It doesn't work well though if there are more than one of the same link)
private void RichTextBoxLinkClicked(object sender, LinkClickedEventArgs e) {
int caret = ((RichTextBox) sender).Text.IndexOf(e.LinkText);
SelectionStart = caret;
}
Edit2 A second solution that I found is to set the focus of the text-box on a MouseEnter event. I've come to think the key to the problem is to set the focus of the text boxes before any user interaction takes place, but I'm having problems finding a satisfactory way to achieve it.

I am trying to create new button in C# but i think my syntax is not proper

So this is my Syntax in the bottom, actually i am making a app launcher, whenever I'll select an exe file it will create a new launch button for it but after running this code i am not getting any response at all, i tried looking the code for making new button but it was same.
This is my code
private void AddNewAppBtn_Click(object sender, RoutedEventArgs e)
{
Functions.addApp();
Button appButton = new Button();
appButton.Content = "Click Me";
appButton.Name = "ButtonA";
var stackPanel = new StackPanel { Orientation = Orientation.Vertical };
stackPanel.Children.Add(appButton);
}
Because you haven't added your Stackpanel to your main Grid or other layout that you want to have the dynamically created Stackpanel. First give your main Grid a name like this:
XAML:
<Grid Name="mainGrid">
Then add this line at the end of your code:
mainGrid.Children.Add(stackPanel);
Just create the button inside the XAML, no code-behind. By doing this and only this, you can implement the MVVM pattern which make your maintainment will less pain.
XAML code:
<Button Content="MyButton"></Button>
Or you want to create a button on cs file. It should be added on your main grid.

Clone ScatterViewItem control in Surface Application

I'm working on a Windows multitouch application using Surface 2.0 SDK.
I need to "clone" a control, in this specific case a ScatterViewItem, in which I've added a ElementMenu with a "CopyButton" with a Click event handler.
This is my ScatterViewItem:
<s:ScatterViewItem x:Name="PhotoPadSVI" MinWidth="296" Background="Transparent" Style="{StaticResource ScatterViewItemStyle}">......</ScatterViewItem>
And this is the code that I used and that doesn't work:
void DocumentDuplicate_Click(object sender, RoutedEventArgs e)
{
ScatterViewItem swi = PhotoPadSVI; //error is already here cause I set it as the same, but I cannot found a ".Clone()" like method
swi.Visibility = System.Windows.Visibility.Visible;
swi.ZIndex = 100;
swi.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
//sView.Items.Add(swi); cannot add to ScatterView cause swi is equal to PhotoPadSVI
}
Question: Do you know in which way could I replicate the ScatterViewItem?
You need to construct a new instance of ScatterViewItem. It should work if you set its Content the same as PhotoPadSVI's.
ScatterViewItem swi = new ScatterViewItem() { Content = PhotoPadSVI.Content };
If there is still error indicating you can't add the same item to ScatterView, you have to do from scratch, create the new ScatterViewItem's Content from code, this can be a lot more complicated if PhotoPadSVI's Content is a bunch of XAML code.
Also refer to this blog.

Voice Enabled RichTextBox

I am trying to create a WPF application that has a richtextbox which accepts dictations from the user as its input.
I want to use this code for the SpeechRecognized event for an an object of the SpeechRecognitionEngine class.
private void speechRecognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
e.Result.Text = rtb.Text; //rtb is an object of the RichTextBox class
}
The problem is that there is no Text property for the RichTextBox class. Is there any way of fixing this? Thanks in advance
Try this:
private void speechRecognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
rtb.AppendText(e.Result.Text);
}
This is a well documented problem and there are many different solutions for it. You can find a large number of possible solutions in the answers to the RichTextBox (WPF) does not have string property “Text” question here on Stack Overflow.
However, my preferred method would be to declare a Text Attached Property for the RichTextBox class. Please see the Attached Properties Overview page on MSDN to find out more about Attached Properties. You can find out what code to use in your Text Attached Property for the RichTextBox class in the RichTextBox Text property where are you hiding? tutorial on C# Disciples website.
RichTextBox contents can be set via Document property. You can find more details on MSDN
Here is an example from the link provided above. It creates a new document and a paragraph for it, then assigns the document to RichTextBox:
// Create a simple FlowDocument to serve as content.
FlowDocument flowDoc = new FlowDocument(new Paragraph(new Run("Simple FlowDocument")));
// Create an empty, default RichTextBox.
RichTextBox rtb = new RichTextBox();
// This call sets the contents of the RichTextBox to the specified FlowDocument.
rtb.Document = flowDoc;
// This call gets a FlowDocument representing the contents of the RichTextBox.
FlowDocument rtbContents = rtb.Document;

WPF cut, copy, paste functionality on a user control

I have a canvas on which you can add UserControls (consists of images and textboxes)
Im trying to implement cut, copy, paste functionality on these UserControls, so the context menu is attatched to a UserControl which deals with images for example. A user right clicks here and from the context menu picks copy for instance how would I then go about implementing so they can paste this on to the canvas.
Can anyone point me in the right direction...
This can be done with RoutedCommands. A full overview is at MSDN: Commanding Overview
The short version is this: when a command source (i.e. a menu item) wants to execute a command, an event is raised. That event is handled by the nearest command binding. Cut/copy/paste commands are already included with WPF, and certain elements (namely, text boxes) already include command bindings for them.
You can define a menu item like this:
<MenuItem Header="Copy" Command="ApplicationCommands.Copy" />
And add a command binding to the UserControl like this:
<UserControl.CommandBindings>
<CommandBinding Command="ApplicationCommands.Copy"
Executed="Copy_Executed" />
</UserControl.CommandBindings>
And define the Copy_Executed method with the ExecutedRoutedEventHandler signature in the UserControl's code-behind.
Then of course do the same thing for ApplicationCommands.Paste within the canvas.
It's up to you whether you want to handle the data within your own application, or use the clipboard. If you're working with images, WPF has a Clipboard class which can work with BitmapSource objects (if you have an Image element, chances are its Source is already a BitmapSource).
Firstly, a well designed MVVM application can make copy/paste of user controls much simpler since it will turn to serialize/deserialize CLR objects to Clipboard. WPF will handle user control creation by itself after deserialization.
If your application does not implement MVVM. You can use XamlWriter/XamlReader to save user controls to XAML and recreate them by yourself. An example:
StringBuilder outstr = new StringBuilder();
//this code need for right XML fomating
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
XamlDesignerSerializationManager dsm =
new XamlDesignerSerializationManager(XmlWriter.Create(outstr, settings));
//this string need for turning on expression saving mode
dsm.XamlWriterMode = XamlWriterMode.Expression;
XamlWriter.Save(control, dsm);
//Read control from XAML
var frameObject = XamlReader.Parse(outstr.ToString()) as UserControl;
if (frameObject != null)
stackPanel.Children.Add(frameObject);
For the part of how to put the XAML string or serialized stream into Clipboard, you can refer to MSDN.
Hope it can help.
If you want to bind the command (as #nmclean explains) from code, you can use:
CommandBindings.Add(new CommandBinding(
ApplicationCommands.Copy,
(sender, args) => { /* logic here */ }));

Categories

Resources