This is a migrated thread and some comments may be shown as answers.

How to create a two way binding between a DocX Byte[] and a RadRichTextBox

2 Answers 235 Views
RichTextBox
This is a migrated thread and some comments may be shown as answers.
Nathan
Top achievements
Rank 1
Nathan asked on 12 Dec 2014, 11:12 PM
In my view model I have a byte[] (called "DocumentBytes") that is read from a .docx file.  I have my view set up like this:

<telerik:DocxDataProvider
  x:Name="docxDataProvider"
  Docx="{Binding DocumentBytes, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
  RichTextBox="{Binding ElementName=SnippetPreviewRichTextBox}"
  />
 
<telerik:RadRichTextBox x:Name="SnippetPreviewRichTextBox"/>

The rich textbox correctly displays the document from the file.  When the user makes a change to the content of the rich textbox and then the textbox loses focus, I need the byte[] (DocumentBytes) to be written back with the updated contents of the textbox, and in the docx format, as it was provided to the DocxDataProvider.

Out-of-the-box this didn't seem to work.  I expected the data provider to just write the value back to my property, but it didn't do that.

So, I tried to implement this myself using my view's code behind:
private bool DocumentHasChanged { get; set; }
 
private void SnippetPreviewRichTextBox_GotFocus(object sender, RoutedEventArgs e)
{
  this.DocumentHasChanged = false;
}
 
private void SnippetPreviewRichTextBox_LostFocus(object sender, RoutedEventArgs e)
{
  if (!this.DocumentHasChanged)
    return;
  var viewModel = this.DataContext as SnippetPreviewViewModel;
  if (viewModel == null)
    return;
 
  var formatProvider = new DocxFormatProvider();
  var docXBytes = formatProvider.Export(this.SnippetPreviewRichTextBox.Document);
  viewModel.DocumentBytes = docXBytes;
}
 
private void SnippetPreviewRichTextBox_DocumentContentChanged(object sender, EventArgs e)
{
  this.DocumentHasChanged = true;
}


This caused problems and threw exceptions when I would edit the document's content in the rich textbox, and then click on back on it (the LostFocus event was firing each time I clicked on the rich textbox).

I'm really surprised there isn't a short and concise example in the WPF documentation on this, and it's something I imagine most people have to do.  Perhaps the documentation is there and I just haven't found it.

So, what I'm looking for is a example of how to actually bind a byte[] from my view model, and get the view to write back to that same property when the rich textbox's content is updated.

2 Answers, 1 is accepted

Sort by
0
Accepted
Petya
Telerik team
answered on 17 Dec 2014, 05:55 PM
Hello Nathan,

Please make sure to set the UpdateSourceTrigger property of the data provider, not the binding:
<telerik:DocxDataProvider x:Name="docxDataProvider" Docx="{Binding DocumentBytes, Mode=TwoWay}" UpdateSourceTrigger="LostFocus" RichTextBox="{Binding ElementName=SnippetPreviewRichTextBox}" />
This should cause your property to update when the control loses focus.

Unfortunately, there is no way to prevent the behavior concerning the LostFocus event of RadRichTextBox. The reason the event is fired is the fact that the caret in control is represented by a TextBox, so focus is passed along to it when you edit the document. I'm afraid I have no suggestions on how you could prevent the behavior.

As to the approach you tried implementing yourself, I couldn't say what is causing this. Can you share the stack trace of the error? Also, please specify the version of Telerik UI for WPF that you are using.

Regards,
Petya
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
0
Nathan
Top achievements
Rank 1
answered on 17 Dec 2014, 10:47 PM
Thanks for the response Petya.

The UpdateSourceTrigger property was the trick.  I ended up not going with LostFocus because of the extra calls that happen when you click into it (I have side effects that happen when the byte[] gets values set to it), and I wanted to control the push of the bytes only when lost focus, if the document has changed.

So I ended up going with this in my View's Xaml

<telerik:DocxDataProvider  x:Name="docxDataProvider"  Docx="{Binding DocumentBytes, Mode=TwoWay}" UpdateSourceTrigger="Explicit"  RichTextBox="{Binding ElementName=SnippetPreviewRichTextBox}"  />
 
<telerik:RadRichTextBox x:Name="SnippetPreviewRichTextBox"/>


And this in the code behind

private bool DocumentHasChanged { get; set; }
 
private void SnippetPreviewRichTextBox_GotFocus(object sender, RoutedEventArgs e)
{
  this.DocumentHasChanged = false;
}
 
private void SnippetPreviewRichTextBox_LostFocus(object sender, RoutedEventArgs e)
{
  if (!this.DocumentHasChanged)
    return;
 
  this.docxDataProvider.UpdateBytes();
}
 
private void SnippetPreviewRichTextBox_DocumentContentChanged(object sender, EventArgs e)
{
  this.DocumentHasChanged = true;
}
 
private void SnippetPreviewRichTextBox_DocumentChanged(object sender, EventArgs e)
{
  this.DocumentHasChanged = false;
}
Tags
RichTextBox
Asked by
Nathan
Top achievements
Rank 1
Answers by
Petya
Telerik team
Nathan
Top achievements
Rank 1
Share this question
or