We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

Requests with GridHyperlinkColumn

Hello,

I use a SfDataGrid and I would like to use the GridHyperlinkColumn to navigate to the detail's page of a row.

But I meet 2 problems:

1 - the rendering of the cell:

in your samples, the cell has a different color, so the user undetstands that he must click here:
sample

but in my app, it's not the case:
problem

I tried to set the style directly as described here, but this didn't change anything...
how-to-style-hyperlink-column

=> would you have an idea?


2 - navigate through the ViewModel:

The GridHyperlinkColumn uses the CurrentCellRequestNavigate event to raises the navigation. 

=> I can use Messenger to interact with my ViewModel, but is there a proper way to do it through a Command and the ViewModel?





15 Replies

JG Jai Ganesh S Syncfusion Team November 7, 2016 11:13 AM UTC

Hi Christophe, 
Please find the response for your queries as below, 
Query 1: 
We have checked the reported issue in our sample but its working fine in our end.  
<Style TargetType="HyperlinkButton"> 
            <Setter Property="Foreground" Value="Green" /> 
</Style> 
 
If still issue occurs, then could you please let us know, how you generate the columns in SfDataGrid and share the more details. This would be more helpful for us to analyze the issue further. 
Query 2: 
You can wiring the CurrentCellRequestNavigate event through command in viewmodel by using below code, 
 
            <interact:Interaction.Behaviors> 
                <core:EventTriggerBehavior EventName="CurrentCellRequestNavigate"> 
                    <core:InvokeCommandAction Command="{Binding CurrentCellRequestNavigateCommand}"  /> 
                </core:EventTriggerBehavior> 
            </interact:Interaction.Behaviors> 
 
public void Navigate(object args) 
        { 
            string str = "http://www.Syncfusion.com"; 
            Launcher.LaunchUriAsync(new Uri(str)); 
        } 
 
Regards, 
Jai Ganesh S 



PD Pierre-Christophe DUS November 30, 2016 08:59 AM UTC

Thanks for your response.
Your sample works for me too, but it's not the case of my my project.

My XAML looks like this:
<!-- DataGrid -->
<grid:SfDataGrid x:Name="sfDataGrid" Grid.Row="1"
Padding="0,10,0,0"
ItemsSource="{Binding Forms}"
SelectedItem="{Binding SelectedForm, Mode=TwoWay}"
AutoGenerateColumns="False"
ColumnSizer="Star"
NavigationMode="Row"
HeaderRowHeight="50">
<grid:SfDataGrid.Columns>
<!-- Form Number -->
<grid:GridHyperlinkColumn MappingName="form_code"
 helpers:SfDgColumnSizerAttachedProperty.ColumnSizer="2">
<grid:GridHyperlinkColumn.HeaderTemplate>
<DataTemplate>
<TextBlock x:Uid="HomeSfColumnFormCodeTextBlock"
  TextAlignment="Center"
  TextWrapping="Wrap" />
</DataTemplate>
</grid:GridHyperlinkColumn.HeaderTemplate>
</grid:GridHyperlinkColumn>
<!-- Submitter -->
<grid:GridTextColumn x:Uid="HomeSfColumnSubmitter"
MappingName="submitterName" 
helpers:SfDgColumnSizerAttachedProperty.ColumnSizer="3"/>
<!-- Company -->
<grid:GridTextColumn x:Uid="HomeSfColumnCompany"
MappingName="company" />
<!-- Submission date -->
<grid:GridTextColumn DisplayBinding="{Binding validation_date, Converter={StaticResource DateFormatConverter}}"
helpers:SfDgColumnSizerAttachedProperty.ColumnSizer="2">
<grid:GridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock x:Uid="HomeSfColumnSubmissionDateTextBlock"
  TextAlignment="Center"
  TextWrapping="Wrap" />
</DataTemplate>
</grid:GridTextColumn.HeaderTemplate>
</grid:GridTextColumn>
<!-- Status -->
<grid:GridTextColumn x:Uid="HomeSfColumnStatus"
MappingName="statusLabel" 
helpers:SfDgColumnSizerAttachedProperty.ColumnSizer="2"/>
<!-- ... more columns -->
</grid:SfDataGrid.Columns>
</grid:SfDataGrid>
=> the content of the GridHyperlinkColumn is always displayed without any accent color, but I can well click in the content to navigate to my details page.

I also tried to apply a custom style to the HyperlinkButton, but it didn't change anything:
<grid:SfDataGrid.Resources>
<Style TargetType="HyperlinkButton">
<Setter Property="Foreground" Value="Red" />
</Style>
</grid:SfDataGrid.Resources>

I specify that content of the column is not a URL, but just a string: the "id" of the form that is opened when the user click on it's name.
For doing this, I use the "OnSfDataGridCurrentCellRequestNavigate":
async void OnSfDataGridCurrentCellRequestNavigate(object sender, CurrentCellRequestNavigateEventArgs args)
{
var form = args.RowData as Forms;        
var viewModel = this.DataContext as HomeViewModel;
viewModel.ClickedForm = form;
viewModel.OpenForm();
}
=> this works well, so I don't understand why I encounter a problem with the render of the GridHyperlinkColumn...

Thanks in advance for your return!

Pierre-Christophe


JG Jai Ganesh S Syncfusion Team December 1, 2016 12:44 PM UTC

Hi Christophe,  
 
We suspect that you have write the style for TextBlock in your application. Hence the HyperLinkColumn Foreground color is not applied.  
 
Could you please check this in your end and please share your Xaml file or if possible please replicate the issue in our sample? This would be more helpful for us to analyze further. 
 
Regards, 
Jai Ganesh S 



PD Pierre-Christophe DUS December 1, 2016 03:18 PM UTC

Yes you're right: I have redefined the TextBlock default style, to globally affect a specific "font color" to the app. Then I use TextBlock style as base for some "specific" TextBlocks.
This is a part of the style:
<Style TargetType="TextBlock">
    <Setter Property="Foreground" Value="{StaticResource FontColor}" />
</Style>
    
<Style x:Key="AppTitleTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource BaseTextBlockStyle}">
    <Setter Property="Margin" Value="12,6,0,6" />
    <Setter Property="VerticalAlignment" Value="Center" />
</Style>

<Style x:Key="ParagraphTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}">
    <Setter Property="Margin" Value="0,1,0,34" />
    <Setter Property="TextWrapping" Value="Wrap" />
    <Setter Property="TextTrimming" Value="CharacterEllipsis" />
</Style>
    
<Style x:Key="TitleTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}">
    <Setter Property="Margin" Value="0,1,0,18" />
</Style>

...

=> Is it possible to keep my custom TextBlock style? Or do I neet to remove it to use the GridHyperlinkColumn style?

Regards,






JG Jai Ganesh S Syncfusion Team December 5, 2016 10:13 AM UTC

Hi Christophe, 
You can achieve your requirement to apply the style for GridHyperLinkColumn by customizing the GridCellHyperLinkRenderer and clear the TextBlock style like below, 
this.sfGrid.CellRenderers.Remove("Hyperlink"); 
this.sfGrid.CellRenderers.Add("Hyperlink", new CustomCellRendererExt());  
 
public class CustomCellRendererExt : GridCellHyperlinkRenderer 
{ 
    public override void OnInitializeEditElement(DataColumnBase dataColumn, HyperlinkButton uiElement, object dataContext) 
    { 
        base.OnInitializeEditElement(dataColumn, uiElement, dataContext); 
        var column = dataColumn.GridColumn; 
        uiElement.SetValue(FrameworkElement.MarginProperty, column.Padding); 
        uiElement.SetValue(Control.PaddingProperty, column.Padding); 
        uiElement.SetValue(Control.VerticalAlignmentProperty, column.VerticalAlignment); 
        var hyperLinkColumn = (GridHyperlinkColumn)column; 
 
        var textBlock = new TextBlock(); 
        uiElement.Content = textBlock; 
        textBlock.SetBinding(TextBlock.TextProperty, column.ValueBinding); 
        if (hyperLinkColumn == null) 
            return; 
 
        textBlock.Style = null; 
 
        textBlock.SetValue(TextBlock.TextWrappingProperty, hyperLinkColumn.TextWrapping); 
 
        uiElement.SetValue(TextBlock.TextWrappingProperty, hyperLinkColumn.TextWrapping); 
        uiElement.SetValue(Control.HorizontalAlignmentProperty, hyperLinkColumn.HorizontalAlignment); 
    } 
}  
 
 
Regards, 
Jai Ganesh S 



PD Pierre-Christophe DUS January 12, 2017 11:28 AM UTC

Thanks for your sample.
But is there a way to render the content of the HyperLinkButton always underlined, as a hyperlink?


SR Sivakumar R Syncfusion Team January 13, 2017 01:08 PM UTC

Hi Christophe, 
 
You can show underlined text in GridHyperlinkColumn by overriding GridCellHyperlinkRenderer as in the below code, We have modified the sample also, 
 
public class CustomCellRendererExt : GridCellHyperlinkRenderer 
{ 
    public override bool CanUpdateBinding(GridColumn column) 
    { 
        return true; 
    } 
 
    public override void OnUpdateEditBinding(DataColumnBase dataColumn, HyperlinkButton element, object dataContext) 
    { 
        var textblock = element.Content as TextBlock; 
        if (textblock == null || textblock.Inlines.Count == 0) 
            return; 
 
        var underline = textblock.Inlines[0] as Underline; 
        var run = underline.Inlines[0] as Run; 
             
        var displayval = this.DataGrid.View.GetPropertyAccessProvider().GetFormattedValue(dataContext, dataColumn.GridColumn.MappingName); 
        run.Text = displayval == null ? string.Empty : displayval.ToString(); 
        base.OnUpdateEditBinding(dataColumn, element, dataContext); 
    } 
 
    public override void OnInitializeEditElement(DataColumnBase dataColumn, HyperlinkButton uiElement, object dataContext) 
    { 
        base.OnInitializeEditElement(dataColumn, uiElement, dataContext); 
        var column = dataColumn.GridColumn; 
        uiElement.SetValue(FrameworkElement.MarginProperty, column.Padding); 
        uiElement.SetValue(Control.PaddingProperty, column.Padding); 
        uiElement.SetValue(Control.VerticalAlignmentProperty, column.VerticalAlignment); 
        var hyperLinkColumn = (GridHyperlinkColumn)column; 
 
        var textBlock = new TextBlock(); 
        uiElement.Content = textBlock; 
        //textBlock.SetBinding(TextBlock.TextProperty, column.ValueBinding); 
        if (hyperLinkColumn == null) 
            return; 
 
        var underline = new Underline(); 
        var run = new Run(); 
        var displayval = this.DataGrid.View.GetPropertyAccessProvider().GetFormattedValue(dataContext, dataColumn.GridColumn.MappingName); 
        run.Text = displayval == null ? string.Empty : displayval.ToString(); 
        underline.Inlines.Add(run); 
        textBlock.Inlines.Add(underline); 
        textBlock.Style = null; 
             
        textBlock.SetValue(TextBlock.TextWrappingProperty, hyperLinkColumn.TextWrapping); 
        uiElement.SetValue(TextBlock.TextWrappingProperty, hyperLinkColumn.TextWrapping); 
        uiElement.SetValue(Control.HorizontalAlignmentProperty, hyperLinkColumn.HorizontalAlignment); 
    } 
} 
 
Sample: 
 
 
Thanks, 
Sivakumar 



PD Pierre-Christophe DUS February 3, 2017 08:32 AM UTC

Thanks for your feedback: this works now fine!
But I have a new request: is it possible to rendering "clickable" the full cell containing the GridHyperlinkColumn?
For exemple all the green area:
Request


JG Jai Ganesh S Syncfusion Team February 8, 2017 03:14 AM UTC

Hi Christophe,  
You can achieve your requirement to do the navigation while clicking anywhere of the GridHyperlinkCell by override the SetFocus method and call the navigation url directly in it.  
protected async override void SetFocus(FrameworkElement uiElement, bool needToFocus) 
{ 
    base.SetFocus(uiElement, needToFocus); 
 
    var hyperlinkControl = (HyperlinkButton)uiElement; 
 
    GridCell gridcell = null; 
 
    if (hyperlinkControl.Parent is GridCell) 
        gridcell = hyperlinkControl.Parent as GridCell; 
 
    var navigateText = string.Empty; 
    var rowColumnIndex = RowColumnIndex.Empty; 
    rowColumnIndex.RowIndex = gridcell != null ? gridcell.ColumnBase.RowIndex : new RowColumnIndex().RowIndex; 
 
    rowColumnIndex.ColumnIndex = gridcell != null ? gridcell.ColumnBase.ColumnIndex : new RowColumnIndex().ColumnIndex; 
 
    if (rowColumnIndex != null && !rowColumnIndex.IsEmpty) 
    { 
        //Get the column from rowColumnIndex. 
        var column = this.DataGrid.Columns[this.DataGrid.ResolveToGridVisibleColumnIndex(rowColumnIndex.ColumnIndex)]; 
 
 
        var recordIndex = this.DataGrid.ResolveToRecordIndex(rowColumnIndex.RowIndex); 
        if (recordIndex < 0) 
            return; 
        var record1 = this.DataGrid.View.Records.GetItemAt(recordIndex); 
        navigateText = record1.GetType().GetProperty(column.MappingName).GetValue(record1).ToString(); 
                
    } 
             
    const string pattern = @"((http|https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)"; 
 
    if (navigateText != null) 
    { 
        var NavigateUri = Regex.IsMatch("http://www.Syncfusion.com", pattern) 
                            ? new Uri("http://www.Syncfusion.com") 
                            : null; 
        if (NavigateUri == null) 
            return; 
 
        hyperlinkControl.NavigateUri = NavigateUri; 
 
        await Launcher.LaunchUriAsync(new Uri(hyperlinkControl.NavigateUri.AbsoluteUri)); 
    } 
} 
 
In the above sample, we have set the navigation url inside the SetFocus method and in this case the CurrentCellRequestNavigate event will not be fired while clicking other part of the cell. 
 
Regards, 
Jai Ganesh S 



PD Pierre-Christophe DUS March 27, 2017 01:46 PM UTC

Hello,

I'm sorry to come back a few weeks after your reply, but I need more help.

In your sample, you use the CurrentCellRequestNavigateCommand Command and the Navigate() method for both cases: the click on the label of the GridHypeLinkColumn and the click outside of the label.

But I don't see how to adapt the code to make it works with paramters. I would like to specify the current id of the row for the clicked cell.
Is it possible by basing on your last sample?

Until now, I was doing this:
async void OnSfDataGridCurrentCellRequestNavigate(object sender, CurrentCellRequestNavigateEventArgs args)
{
    var carForm = args.RowData as Car_Forms;        
    var viewModel = this.DataContext as HomeViewModel;
    viewModel.ClickedCarForm = carForm;
    viewModel.OpenForm();
}

But in your sample, the SetFocus() method is not in the same classe, so I can't access directly to my ViewModel...

Regards,


JG Jai Ganesh S Syncfusion Team March 29, 2017 11:17 AM UTC

Hi Christophe,   
You can achieve your requirement to passing the parameters while calling the CurrentCellRequestNavigate event by raising the CurrentCellRequestNavigate event with parameters in SetFocus method like below, 
 
protected async override void SetFocus(FrameworkElement uiElement, bool needToFocus) 
{ 
    base.SetFocus(uiElement, needToFocus); 
 
    var hyperlinkControl = (HyperlinkButton)uiElement; 
 
    hyperlinkControl.FontStretch = Windows.UI.Text.FontStretch.UltraExpanded; 
    GridCell gridcell = null; 
 
    if (hyperlinkControl.Parent is GridCell) 
        gridcell = hyperlinkControl.Parent as GridCell; 
 
    var navigateText = string.Empty; 
    var rowColumnIndex = RowColumnIndex.Empty; 
    rowColumnIndex.RowIndex = gridcell != null ? gridcell.ColumnBase.RowIndex : new RowColumnIndex().RowIndex; 
 
    rowColumnIndex.ColumnIndex = gridcell != null ? gridcell.ColumnBase.ColumnIndex : new RowColumnIndex().ColumnIndex; 
 
    if (rowColumnIndex != null && !rowColumnIndex.IsEmpty) 
    { 
        //Get the column from rowColumnIndex. 
        var column = this.DataGrid.Columns[this.DataGrid.ResolveToGridVisibleColumnIndex(rowColumnIndex.ColumnIndex)]; 
 
 
        var recordIndex = this.DataGrid.ResolveToRecordIndex(rowColumnIndex.RowIndex); 
        if (recordIndex < 0) 
            return; 
        var record1 = this.DataGrid.View.Records.GetItemAt(recordIndex); 
        navigateText = record1.GetType().GetProperty(column.MappingName).GetValue(record1).ToString(); 
 
    } 
 
    MethodInfo dynMethod = this.DataGrid.GetType().GetMethod("CurrentCellRequestNavigateEvent", 
    BindingFlags.NonPublic | BindingFlags.Instance); 
 
    CurrentCellRequestNavigateEventArgs ob = new CurrentCellRequestNavigateEventArgs(DataGrid); 
 
    ob.GetType().GetProperty("NavigateText").SetValue(ob, navigateText); 
    ob.GetType().GetProperty("RowData").SetValue(ob, hyperlinkControl.DataContext); 
    ob.GetType().GetProperty("RowColumnIndex").SetValue(ob, rowColumnIndex); 
 
    dynMethod.Invoke(DataGrid, new object[] { ob }); 
} 
 
 
Regards, 
Jai Ganesh S 



PD Pierre-Christophe DUS March 30, 2017 09:00 AM UTC

Thank you, it's almost perfect like that!
The last problem is that the Navigate() method of the ViewModel is called 2 times when the user click on the hyperlink.
Is there a way to fix this properly, or do I need to add a boolean to disabled the navigation?
Regards,



JG Jai Ganesh S Syncfusion Team March 31, 2017 10:50 AM UTC

Hi Christophe, 
 
In our sample, we have raised the CurrentCellRequestNavigateEvent from the SetFocus method to achieve your requirement. Hence the Navigate method calling two times. However, you can resolve this by using the flag like below, 
private bool isNavigate = false; 
public void Navigate(object args) 
{ 
    if (!isNavigate) 
    { 
        string str = "http://www.Syncfusion.com"; 
        Launcher.LaunchUriAsync(new Uri(str)); 
        isNavigate = true; 
    } 
} 
 
 
Regards, 
Jai Ganesh S 



PD Pierre-Christophe DUS March 31, 2017 02:03 PM UTC

Thanks again for your feedback.

I have on more question: in my case, I use the SfDataGrid with the NavigationMode="Row", as the grid is only used for displaying data:


But if we use this parameter in your sample, the SetFocus() is not longer fired when a user click in the cell:
<syncfusion:SfDataGrid x:Name="sfGrid"
           Grid.Row="1"
           NavigationMode="Row"
          SelectionMode="Extended"
          AddNewRowPosition="Top"
          AllowEditing="True"
          AllowFiltering="True"
          AutoGenerateColumns="False"
          GridValidationMode="InView"
          ItemsSource="{Binding UserDetails}"
         ShowRowHeader="True">

But if we remove this parameter, there is a "border" around the current cell:


Is is possible to remove this border?
Or do we can update the code to make it work with the parameter  NavigationMode="Row"?






JG Jai Ganesh S Syncfusion Team April 3, 2017 10:45 AM UTC

Hi Christophe, 
 
The SetFocus() method will not be fired when the NavigationMode as Row. This is the default behavior of SfDataGrid. However, you can achieve your requirement for removing curentcell border by setting CurrentCellBorderThickness as 0, 
 
<syncfusion:SfDataGrid x:Name="sfGrid" 
                                   Grid.Row="1" 
                                   SelectionMode="Extended" 
                                   AddNewRowPosition="Top" 
                                   AllowEditing="True" 
                                   AllowFiltering="True" 
                                   CurrentCellBorderThickness="0" 
                                   AutoGenerateColumns="False" 
                                   GridValidationMode="InView" 
                                   ItemsSource="{Binding UserDetails}" 
                                   ShowRowHeader="True"/> 
 
Regards, 
Jai Ganesh S 


Loader.
Up arrow icon