Home Forums WPF controls Xceed DataGrid for WPF Accessing datarow from template & using RichTextBox

Viewing 10 posts - 1 through 10 (of 10 total)
  • Author
    Posts
  • User (Old forums)
    Member
    Post count: 23064
    #24351 |

    Hi group, I have a couple of (maybe naive, I’m just experimenting) related questions, I’ll make a fake sample to be clearer: let’s say I’m binding to a (readonly) data table which has among others 4 relevant fields:

    1) firstName;
    2) lastName;
    3) a generic text field;
    4) marking(s) for (3), which define text run(s) to be displayed with a different formatting in a rich text box: for instance, if text is “This is a sample” the markings field may contain a string like “5×2” telling me that the 2-chars run beginning at index 5 (i.e. the word “is”) must be formatted in some way.

    Now I’d like to display these fields into a grid, so that:

    1) a unique cell contains first + last names;
    2) another cell contains a rich text box formatted using the markings field.

    As for (1) I should use a DataTemplate which can access 2 different fields from the same row and join them, e.g. using a horizontal StackPanel with 2 TextBlock’s. The first question is thus: how do I access more than 1 field from a data template referring to a bound column? In other words, I’d like some way of accessing the datarow fields from a XAML data template applied to a grid column, but in a bound column {Binding} refers just to the bound field.

    As for (2), I’d think of using a value converter getting as input the text and the markings, and outputting something like a flow document. But, a) how can I pass to the converter 2 different fields from the same row? and b) is it possible to bind the content to a rich text box?

    Thanx!

    Imported from legacy forums. Posted by Mathetes (had 1024 views)

    Xceed Support
    Member
    Post count: 5658

    What I think you might need to do is create a CellContentTemplate for 4 out of the 2 columns (the ones in which you want the actual content to the displayed. In the first DataTemplate, you can then have, for example, a StackPanel that contains TextBlock and whose Text properties are bound to the the columns that have the information you require.

    For 2, I did exactly this in an application. First, you can’t bind the Text property of a run (one of the great WPF mysteries if you ask me) so you would need to create something like a “bindable run” (i’ll post the code in the next post) whose “BindableText” property you can then bind to the formatted text.

    If you want to use a FlowDocument, use the FlowDocumentScrollViewer, it’s your best option sinceI doubt you want the user to edit the content. The Document property of the FDSV is also not-bindable so you would need to create either a “bindable FDSV”, or a bindable “BindableDocument” attached property (code in next post). What I did in my application is highlight keywords using a converter that made a Paragraph object that contained all the runs, both highlighted and not, in the order in which I needed them (code in next post). This converter was assigned to the BindableDocument property but assumed that only one text was used.

    Hope this helps!

    Imported from legacy forums. Posted by Jenny [Xceed] (had 529 views)

    Xceed Support
    Member
    Post count: 5658

    OK. My remote connection is not working so I will post what I have here. The BindableExtender class contains both the BindableText and BindableDocument attached properties.

    <code>
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Documents;
    using System.Windows.Controls;

    namespace SnippetExplorer
    {
    public static class BindableExtender
    {
    public static string GetBindableText( DependencyObject obj )
    {
    return ( string )obj.GetValue( BindableTextProperty );
    }

    public static void SetBindableText( DependencyObject obj, string value )
    {
    obj.SetValue( BindableTextProperty, value );
    }

    public static readonly DependencyProperty BindableTextProperty =
    DependencyProperty.RegisterAttached( “BindableText”, typeof( string ), typeof( BindableExtender ), new UIPropertyMetadata( null, BindableTextProperty_PropertyChanged ) );

    private static void BindableTextProperty_PropertyChanged(
    DependencyObject dependencyObject,
    DependencyPropertyChangedEventArgs e )
    {
    if( dependencyObject is Run )
    {
    ( ( Run )dependencyObject ).Text = ( string )e.NewValue;
    }
    }

    // Bindable Document Property
    public static string GetBindableDocument( DependencyObject obj )
    {
    return ( string )obj.GetValue( BindableDocumentProperty );
    }

    public static void SetBindableDocument( DependencyObject obj, FlowDocument value )
    {
    obj.SetValue( BindableDocumentProperty, value );
    }

    public static readonly DependencyProperty BindableDocumentProperty =
    DependencyProperty.RegisterAttached( “BindableDocument”, typeof( FlowDocument ), typeof( BindableExtender ), new UIPropertyMetadata( null, BindableDocumentProperty_PropertyChanged ) );

    private static void BindableDocumentProperty_PropertyChanged(
    DependencyObject dependencyObject,
    DependencyPropertyChangedEventArgs e )
    {
    if( dependencyObject is FlowDocumentScrollViewer )
    {
    if( e.NewValue == null )
    {
    ( ( FlowDocumentScrollViewer )dependencyObject ).Document = new FlowDocument();
    }
    else
    {
    ( ( FlowDocumentScrollViewer )dependencyObject ).Document = ( FlowDocument )e.NewValue;
    }
    }
    }
    }
    }

    </code>

    These are old working versions, so they may need to be tweaked. The BindableRun that I mentioned can be a standard Run the uses the BindableText attached property.

    Imported from legacy forums. Posted by Jenny [Xceed] (had 328 views)

    Xceed Support
    Member
    Post count: 5658

    Converter:

    <code>
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Text.RegularExpressions;
    using System.Collections;

    namespace SnippetExplorer
    {
    [ValueConversion( typeof( string ), typeof( FlowDocument ) )]
    public class HighlightConverter : IValueConverter
    {
    public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
    {
    if( ( m_criteria == null ) || ( m_criteria.Length == 0 ) )
    {
    return new FlowDocument( new Paragraph( new Run( value as string ) ) );
    }

    ArrayList list = new ArrayList();
    list.Add( ( string )value );

    foreach( string criterion in m_criteria )
    {
    int index = 0;
    while( index < list.Count )
    {
    if( list[ index ] is string )
    {
    string item = ( string )list[ index ];
    int startIndex = item.ToUpper().IndexOf( criterion );

    if( startIndex >= 0 )
    {
    list.Insert( index + 1, new HighlightRun( item.Substring( startIndex, criterion.Length ) ) );
    list.Insert( index + 2, item.Substring( startIndex + criterion.Length ) );
    list[ index ] = item.Substring( 0, startIndex );
    }
    }

    index++;
    }
    }

    FlowDocument document = new FlowDocument();
    Paragraph para = new Paragraph();

    foreach( object item in list )
    {
    if( item is string )
    {
    para.Inlines.Add( new Run( ( string )item ) );
    }
    else
    {
    para.Inlines.Add( ( HighlightRun )item );
    }
    }

    document.Blocks.Add( para );
    return document;
    }

    public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
    {
    throw new NotImplementedException( “The method or operation is not implemented.” );
    }

    private string[] m_criteria = null;

    public string[] Criteria
    {
    get
    {
    return m_criteria;
    }
    set
    {
    m_criteria = value;
    }
    }

    }
    }

    </code>

    Imported from legacy forums. Posted by Jenny [Xceed] (had 260 views)

    Xceed Support
    Member
    Post count: 5658

    Hope this helps!

    Imported from legacy forums. Posted by Jenny [Xceed] (had 482 views)

    User (Old forums)
    Member
    Post count: 23064

    Wow, thank you very much for your help! Anyway I’m not sure to understand the XAML part: i.e. how to get different fields from a template. E.g. if I have a bound column like:

    <xcdg:DataGridControl … AutoCreateColumns=”False” ReadOnly=”True”>
    <xcdg:DataGridControl.Columns>
    <xcdg:Column FieldName=”lastName” Title=”name” />

    This column is bound to the lastName field only, and in a DataTemplate I could just refer to it using {Binding}. A similar problem occurs for text markings: as the text itself comes from the data row together with its markings, I need to pass 2 values to the converter: the text AND the markings. Anyway, a ConverterParameter cannot be bound…

    Imported from legacy forums. Posted by Mathetes (had 405 views)

    Xceed Support
    Member
    Post count: 5658

    You should leave the AutoCreateColumns property to true and hide the columns you don’t see. That way, you will have access to the other columns as well. Then, you can bind a field (even if it is in the same column) to the value of a cell in another column.

    For example (I am at home and have written this of the top of my head, so it might contain errors):

    <code>

    <xcdg:DataGridControl.Columns>
    <xcdg:Column FieldName=lastName>
    <xcdg:Column.CellContentTemplate>
    <DataTemplate>
    <StackPanel Orientation=Horizontal>
    <TextBlock Text=”{Binding firstName}”/>
    <TextBlock Text=” “/>
    <TextBlock Text=”{Binding lastName}”/>
    </StackPanel>
    </DataTemplate>
    </xcdg:Column.CellContentTemplate>
    </xcdg:Column FieldName=lastName>
    </xcdg:DataGridControl.Columns>

    </code>

    As for the converter, you can always pass the first text with the converterparameter set to the markings you want and then the second. You might need to fiddle around some to get it to work like you want it to.

    Imported from legacy forums. Posted by Jenny [Xceed] (had 307 views)

    User (Old forums)
    Member
    Post count: 23064

    Thanks again! Anyway, I’ve tried your suggestion but I must be doing something wrong: the binding does not find the field. In the sample below I’ve tested with 2 fields of a table representing a range (min and max year), trying to show both in a single column: here’s a snippet:

    <xcdg:DataGridControl x:Name=”_dgResults” AutoCreateColumns=”True” ReadOnly=”True”>

    <xcdg:DataGridControl.Columns>
    <xcdg:Column FieldName=”yearMin” Title=”date” Width=”100″>
    <xcdg:Column.CellContentTemplate>
    <DataTemplate>
    <StackPanel Orientation=”Horizontal”>
    <TextBlock Text=”{Binding yearMin}”/>
    <TextBlock Text=”-“/>
    <TextBlock Text=”{Binding yearMax}”/>
    </StackPanel>
    </DataTemplate>
    </xcdg:Column.CellContentTemplate>
    </xcdg:Column>

    Here I just get the “-“, as neither yearMin or yearMax are found, with errors like:

    …System.Windows.Data Error: 35 : BindingExpression path error: ‘yearMax’ property not found on ‘object’ ”Int16′ (HashCode=-20578619)’. BindingExpression:Path=yearMax; DataItem=’Int16′ (HashCode=-20578619); target element is ‘TextBlock’ (Name=”); target property is ‘Text’ (type ‘String’)…

    (BTW, for the converter, both markings and text come from the data source, so I cannot define an a-priori marking in the parameter: both text and textMarks are fields of the underlying data row, so I must find a way to pass both to the converter).

    Imported from legacy forums. Posted by Mathetes (had 605 views)

    Xceed Support
    Member
    Post count: 5658

    Try this instead:

    <TextBlock Text=”{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type xcdg:DataCell}}, Path=DataContext[yearMax]}”/>

    Imported from legacy forums. Posted by Jenny [Xceed] (had 489 views)

    User (Old forums)
    Member
    Post count: 23064

    Thanks, this works!

    Imported from legacy forums. Posted by Mathetes (had 7193 views)

Viewing 10 posts - 1 through 10 (of 10 total)
  • You must be logged in to reply to this topic.