Hello,
Let's start by explaining what I'm trying to achieve. I basically want to bind a single RadRichTextBox to multiple different DataProviders.
In my specific situation one RtfDataProvider and one TxtDataProvider. So that the same text can be bound to two different properties.
Where one property is just plain text and the other has the applied format (rtf).
I just went ahead and just tried it, and to my surprise this actually worked perfectly fine. However when I tried to apply the same technique to a custom RadGridView.RowDetailsTemplate this quit working and only the format of the last defined DataProvider gets applied.
One could think that this isn't really that big of an issue if you just define the RtfDataProver last, because then the RadRichTextBox would always have the correct styles applied.
This train of though would be correct when you can assume that both properties will always contain the same values, which unfortunately is not the case in my specific scenario.
Here is what happened, my model (and corresponding database table) used to only have the property for plain text.
We've recently decided to add an extra property (or column in the database) to save text formatting (rtf).
The great thing about binding both of the properties to the different DataProviders was that even if the rtf-property was empty/null then the RadRichTextBox would still show the plain text and apply default formatting to it.
When using this technique in the RowDetailsTemplate then the following situations occurred:
- RtfDataProvider is defined last: when the rtf-property is empty the RadRichTextBox will always be empty even when the plain text-property has a value.
- TxtDataProvider is defined last: the RadRichTextBox will always show some text but won't apply any formatting to it even when there is some defined in the rtf-property.
To explain my scenario better I'll add some code to helpfully make things easier to understand. (This isn't my actual code, just a simpler version to get help sketch an idea)
1. My basic model that represents the table in our database
public class MyTaskObject : INotifyPropertyChanged{ private long _taskId; public long TaskId { get { return _taskId; } set { SetProperty(ref _taskId, value); } } private string _title; public string Title { get { return _title; } set { SetProperty(ref _title, value); } } private string _text; public string Text { get { return _text; } set { SetProperty(ref _text, value); } } private string _rtfText; public string RtfText { get { return _rtfText; } set { SetProperty(ref _rtfText, value); } } #region Observable public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propName = null) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propName)); } } protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null) { if (Equals(storage, value)) return false; storage = value; OnPropertyChanged(propertyName); return true; } #endregion }
2. The first scenario where binding the 2 properties to different DataProviders and a single RadRichTextBox works perfectly as desired.
2.1 This is the Xaml of the view: it's a simple user control that allows the user to search a the database for a specific "task", load it and edit before saving it.
So imagine there to be a buttons to look for "tasks" and commit or discard the changes.
There are also some textboxes to edit the edit the "Title" property for example, followed by the following:
<telerik:RtfDataProvider x:Name="TaskRtfProvider" Grid.Row="1" Grid.Column="0" RichTextBox="{Binding ElementName=TaskEditor}" SetupDocument="DataProviderBase_OnSetupDocument" Rtf="{Binding SelectedTask.RtfText, Mode=TwoWay, UpdateSourceTrigger=Explicit}" /><telerik:TxtDataProvider x:Name="TaskTxtProvider" Grid.Row="1" Grid.Column="0" RichTextBox="{Binding ElementName=TaskEditor}" SetupDocument="DataProviderBase_OnSetupDocument" Text="{Binding SelectedTask.Text, Mode=TwoWay, UpdateSourceTrigger=Explicit}" /><telerik:RadRichTextBox Grid.Row="1" Grid.Column="0" x:Name="TaskEditor" Margin="5,0" IsImageMiniToolBarEnabled="True" IsSpellCheckingEnabled="False" Padding="4,2" FontSize="11pt" FontFamily="Calibri" LayoutMode="Flow" DocumentInheritsDefaultStyleSettings="True"/>The UpdateSourceTrigger is Explicit because I use changed tracking and only wish to update the database when the user explicitly says to be clicking a button.
Because if I don't do it this way, and the user loads a task where the "RtfText" property is empty, then immediately after loading this will have a value defined by the default formatting of the RadRichTextBox.
In this first scenario these bindings actually work as they're supposed to.
2.2 The implementation of the SetupDocument-event, this is used to apply some basic formatting (mainly to remove excessive spacing between lines)
private void DataProviderBase_OnSetupDocument(object sender, SetupDocumentEventArgs e){ //var test = sender; if (e.Document == null) return; e.Document.ParagraphDefaultSpacingAfter = 0;}While debugging I've noticed that the second defined DataProvider (in this example the "TaskTxtProvider") does always trigger this event, only when the first DataProvider is null does this event get triggered twice.
Which is exactly what makes this scenario work because this way the RadRichTextBox shows the formatted text if there is any, and else applies the default formatting to the plain text.
This is of course the reason for defining the RtfDataProvider ("TaskRtfProvider") first.
3. The second scenario is where this stops working, and where I tried to place a RadRichTextBox into the rows of a RadGridView.
In this scenario the RadRichTextBox is purely used for displaying the data, not editing.
