Richtextbox Wpf Binding

Richtextbox wpf binding

There is a much easier way!

You can easily create an attached DocumentXaml (or DocumentRTF) property which will allow you to bind the RichTextBox's document. It is used like this, where Autobiography is a string property in your data model:

<TextBox Text="{Binding FirstName}" />
<TextBox Text="{Binding LastName}" />
<RichTextBox local:RichTextBoxHelper.DocumentXaml="{Binding Autobiography}" />

Voila! Fully bindable RichTextBox data!

The implementation of this property is quite simple: When the property is set, load the XAML (or RTF) into a new FlowDocument. When the FlowDocument changes, update the property value.

This code should do the trick:

using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
public class RichTextBoxHelper : DependencyObject
{
public static string GetDocumentXaml(DependencyObject obj)
{
return (string)obj.GetValue(DocumentXamlProperty);
}

public static void SetDocumentXaml(DependencyObject obj, string value)
{
obj.SetValue(DocumentXamlProperty, value);
}

public static readonly DependencyProperty DocumentXamlProperty =
DependencyProperty.RegisterAttached(
"DocumentXaml",
typeof(string),
typeof(RichTextBoxHelper),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
PropertyChangedCallback = (obj, e) =>
{
var richTextBox = (RichTextBox)obj;

// Parse the XAML to a document (or use XamlReader.Parse())
var xaml = GetDocumentXaml(richTextBox);
var doc = new FlowDocument();
var range = new TextRange(doc.ContentStart, doc.ContentEnd);

range.Load(new MemoryStream(Encoding.UTF8.GetBytes(xaml)),
DataFormats.Xaml);

// Set the document
richTextBox.Document = doc;

// When the document changes update the source
range.Changed += (obj2, e2) =>
{
if (richTextBox.Document == doc)
{
MemoryStream buffer = new MemoryStream();
range.Save(buffer, DataFormats.Xaml);
SetDocumentXaml(richTextBox,
Encoding.UTF8.GetString(buffer.ToArray()));
}
};
}
});
}

The same code could be used for TextFormats.RTF or TextFormats.XamlPackage. For XamlPackage you would have a property of type byte[] instead of string.

The XamlPackage format has several advantages over plain XAML, especially the ability to include resources such as images, and it is more flexible and easier to work with than RTF.

It is hard to believe this question sat for 15 months without anyone pointing out the easy way to do this.

Binding RichTextBox to a string

You can use RichTextBox(link) from Extended WPF Toolkit.

Example:

<toolkit:RichTextBox x:Name="_richTextBox" Grid.Row="1" Margin="10" BorderBrush="Gray" Padding="10"
Text="{Binding Notes}"
ScrollViewer.VerticalScrollBarVisibility="Auto" />

where toolkit is namespace to Extended WPF Toolkit library:

xmlns:toolkit="http://schemas.xceed.com/wpf/xaml/toolkit" 

Installation guide:

Instructions for using the Extended WPF Toolkit binaries (link):

  1. Install .NET Framework 4.0 or 4.5
  2. Download the ExtendedWPFToolkit_Binaries
  3. Right-click ExtendedWPFToolkit_Binaries.zip -> Properties -> Unblock
  4. Unzip the ExtendedWPFToolkit_Binaries.zip
  5. Add a using statement ("using Xceed.Wpf.Toolkit;") to the top of .cs files
  6. Add a new xmlns (for example, xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit") to the top of XAML files
  7. In your XAML, use the namespace prefix (in the above example, )

Or you can install this library by NuGet (link):

PM> Install-Package Extended.Wpf.Toolkit

Wpf Richtextbox data binding issue: can't get the correct data

Sarina, there is no direct way to bind string variable to RichTextbox. You can find lots of problem statement for the same while searching on google. PreviewKeyDown show current key only so it may not show what was the previous text was.

Simple way

to set RichTextBox text:

Richtextbox.Document.Blocks.Clear();
Richtextbox.Document.Blocks.Add(new Paragraph(new Run("Text")));

to get RichTextBox text:

string richText = new TextRange(Richtextbox.Document.ContentStart, Richtextbox.Document.ContentEnd).Text;

You can use above methods with tricks and get the output you want. You can manually update your model in PreviewKeyDown event.

OR

There are only one permanent solution of this problem is to use attached property where you can put you login to get the text of the RichTextBox. It will help you to get and set you values easily.

This is the basic code for Text property for RichTextBox. You can modify it as per your need as I am not able to write exact you need. But it will surely help you to achieve your need.

public class RichTextBoxHelper
{

/// <summary>
/// Text Attached Dependency Property
/// </summary>
public static readonly DependencyProperty TextProperty =
DependencyProperty.RegisterAttached("Text", typeof(string), typeof(RichTextBoxHelper),
new FrameworkPropertyMetadata((string)null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault |
FrameworkPropertyMetadataOptions.Journal,
new PropertyChangedCallback(OnTextChanged),
new CoerceValueCallback(CoerceText),
true,
UpdateSourceTrigger.PropertyChanged));


/// <summary>
/// Gets the Text property.
/// </summary>
public static string GetText(DependencyObject d)
{
return (string)d.GetValue(TextProperty);
}

/// <summary>
/// Sets the Text property.
/// </summary>
public static void SetText(DependencyObject d, string value)
{
d.SetValue(TextProperty, value);
}

/// <summary>
/// Returns the Text from a FlowDocument
/// </summary>
/// <param name="document">The document to get the text from</param>
/// <returns>Returns a string with the text of the flow document</returns>
public static string GetText(FlowDocument document)
{
return new TextRange(document.ContentStart, document.ContentEnd).Text;
}

/// <summary>
/// Handles changes to the Text property.
/// </summary>
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
RichTextBox textBox = (RichTextBox)d;
if (e.NewValue != null)
{
textBox.Document.Blocks.Clear();
textBox.Document.Blocks.Add(new Paragraph(new Run(e.NewValue.ToString())));
}
}
}

XAML Binding

<RichTextBox Grid.Row="4" Width="200" Height="60" AcceptsReturn="True" AcceptsTab="True" VerticalScrollBarVisibility="Auto" PreviewKeyDown="PreviewKeyDown" local:RichTextBoxHelper.Text="{Binding DisplayText}">
</RichTextBox>

Bind the text of RichTextBox from Xaml

There is no built in way to do that. You can create Text attached property and bind to it like discussed here

Binding the selected text of a RichTextBox to a property in the ViewModel

You could use a Behavior:

public class RichTextSelectionBehavior : Behavior<RichTextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectionChanged += RichTextBoxSelectionChanged;
}

protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.SelectionChanged -= RichTextBoxSelectionChanged;
}

void RichTextBoxSelectionChanged(object sender, System.Windows.RoutedEventArgs e)
{
SelectedText = AssociatedObject.Selection.Text;
}

public string SelectedText
{
get { return (string)GetValue(SelectedTextProperty); }
set { SetValue(SelectedTextProperty, value); }
}

public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.Register(
"SelectedText",
typeof(string),
typeof(RichTextSelectionBehavior),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedTextChanged));

private static void OnSelectedTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = d as RichTextSelectionBehavior;
if (behavior == null)
return;
behavior.AssociatedObject.Selection.Text = behavior.SelectedText;
}
}

XAML usage:

    <RichTextBox>
<i:Interaction.Behaviors>
<local:RichTextSelectionBehavior SelectedText="{Binding SelectedText}" />
</i:Interaction.Behaviors>
</RichTextBox>

(where SelectedText is a string property on your ViewModel)



Related Topics



Leave a reply



Submit