Select to view content in your preferred language

Binding to Hyperlink NavigateURI property.

4778
9
06-30-2010 10:58 AM
StephenSporik
Deactivated User
Hi.  I have implemented a customized MapTip using the MapTip widget.  This is a modification to an older Silverlight 2 application, so I have to use a Dictionary Converter.  Currently I Bind the values to text boxes, but need to change one of the fields to a hyperlink button.

The values stored in the feature class are only relative paths, as we move from development machines to staging machines and eventually production we do not want to have to change our SDE data.

To Bind to the 'NavigateURI' property of a hyperlink button you must have a uri object, and a fully qualified one at that. So binding directly from the Dictionary Converter does not work.  To handle this you can pass a string to a URIconverter class which is referenced in the code behind.

Below is what the XAML would look like using this URIconverter.  My question is how to I get the original value from the Dictionary Converter to the variable "MyString."

      <StackPanel Orientation="Horizontal">
         <TextBlock Text="User Documentation: " Margin="3,0,3,0" />
         <HyperlinkButton x:Name="VAVuserdoc" Content="Open" Tag=""
                                 NavigateUri="{Binding   MyString, Converter ={StaticResource uriConverter}}"
                                 TargetName="_blank" FontWeight="Bold" Margin="3,0,3,0"/>
      </StackPanel>

In other words.  I need to manipulate the value from the Dictionary Converter BEFORE I bind to the NavigateURI property.  Is this possible?
0 Kudos
9 Replies
DominiqueBroux
Esri Frequent Contributor
Probably not easy to chain 2 converters.
The problem is that the 'Binding' class is not a Dependency Object so it's not possible to bind a ConverterParameter.

My suggestion is you to integrate the dictionary converter inside the uriConverter. So you would get an UriDictConverter:
NavigateUri="{Binding Attributes,  Converter ={StaticResource uriDictConverter}, ConverterParameter=UrlField}"


Likely, there are better solutions. Any other ideas?
0 Kudos
StephenSporik
Deactivated User
Yes, I tried to bind to the converterParameter by nesting the binding, but the page wouldn't even compile.

NavigateUri="{Binding {Binding Converter={StaticResource HVACcontrolsDictionaryConverter}, ConverterParameter=USERDOC, Mode=OneWay}, Converter={StaticResource uriConverter}}"

Your suggestion is where I'm headed, but i'm not sure how to pass any values to the converter in the first place.

Your "attributes" input value contains what? and where is it defined?
0 Kudos
dotMorten_esri
Esri Notable Contributor
Probably not easy to chain 2 converters.


You could bind the first "outer" value to the DataContext property of the hyperlinkbutton to get around that limitation. The property you will be binding to in the NavigateUri will then instead be that property and not the Attributes.
0 Kudos
DominiqueBroux
Esri Frequent Contributor
In my example 'Attributes' was the path to the dictionary but I was more thinking to an usage with a feature data grid.
With a maptip, it should rather be 'Path=.' because the framework sets the maptip datacontext to the Attributes dictionary itself.
So:
 
NavigateUri="{Binding Path=.,  Converter ={StaticResource uriDictConverter}, ConverterParameter=UrlField}"

The converter will get the dictionary as input value and the Url attribute as ConverterParameter.
The converter should be something like (not tested):

 
public class UriDictionaryConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {

       IDictionary<string, object> dict = value asIDictionary<string, object>;
       String urlField = parameter as String;
       if (dict != null)
       {
           if (dict.ContainsKey(urlField))
              return  Uri("http://Myserver/" + dict[urlField]);
       }
             return null;
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
0 Kudos
dotMorten_esri
Esri Notable Contributor
For what it's worth (and for people who use Silverlight 4), you can simply use SL4's StringFormat property to create the Url. Example: Search google for the attribute value in 'name':
NavigateUri="{Binding [name], StringFormat=http://www.google.com/search?q\=\{0\}}"
0 Kudos
StephenSporik
Deactivated User
Thanks for the great pointers.  I had to use a combination of the two.  "Path=." would not work for me.  Like Dominique pionted out, have to specify the Key for the UriConverter as the DataContext will store the entire Dictionary, even if you specify your Converter Parameter in the binding of the DataContext property.

You will see I specified the USERDOC field name in the UriConverter binding and then in the code behind I can access that Key/Value pair from the Dictionary object which is passed as the "value" variable.

.....
 
    <xmlns:uri="clr-namespace:HVAC;assembly=HVAC">
    
    <UserControl.Resources>
        <uri:UriConverter x:Name="UriConverter"/>
    </UserControl.Resources>

.....


<HyperlinkButton x:Name="VAVuserdoc" Content="Open" 
DataContext="{Binding Converter={StaticResource HHVACVAVDictionaryConverter}}" NavigateUri="{Binding Converter={StaticResource UriConverter}, ConverterParameter=USERDOC}" TargetName="_blank" FontWeight="Bold" Margin="3,0,3,0"/>

___________________________________________________________________________________
(CODE BEHIND VB.NET)
 
Public Class UriConverter
    Implements IValueConverter

Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert

        Dim path As Uri = Nothing
        If Not value Is Nothing Then
            Dim pathNameBuilder As New UriBuilder
            pathNameBuilder.Scheme = "http"
            pathNameBuilder.Host = "myserver.domain.com"
            pathNameBuilder.Path = "root/directory/" + value(parameter.ToString).ToString
            path = pathNameBuilder.Uri
        End If
        Return path

    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack

        Throw New NotImplementedException()

    End Function

End Class
0 Kudos
Chula_VistaGIS
Occasional Contributor
As someone who is not an experiences programmer, I though I would pass along something I found in looking at this thread.  Using the code below to build a string used for a hyperlink button and datatemplate, I found the value passed to the converter (UriConverter) is the selected graphic, so ... in my converter I can access the dictionary object by getting the selected features of the graphic. 

Does anyone see any downside to taking this approach ?

Dim sb As New StringBuilder
        sb.Append("<DataTemplate ")
        sb.Append("xmlns='http://schemas.microsoft.com/winfx/")
        sb.Append("2006/xaml/presentation' ")
        sb.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ")
        sb.Append("xmlns:local='clr-namespace:<MyNameSpace>;assembly=<MyAssemble>'>")
        sb.Append("<Grid>")
        sb.Append("<Grid.Resources>")
        sb.Append("<local:UriConverter x:Key='UriConverter' />")
        sb.Append("</Grid.Resources>")
        sb.Append("<HyperlinkButton Content='{Binding " & str & "}' TargetName='_blank' ")
        sb.Append("NavigateUri='{Binding Converter={StaticResource UriConverter},ConverterParameter=" & fld & "}' />")
        sb.Append("</Grid>")
        sb.Append("</DataTemplate>")

In my example 'Attributes' was the path to the dictionary but I was more thinking to an usage with a feature data grid.
With a maptip, it should rather be 'Path=.' because the framework sets the maptip datacontext to the Attributes dictionary itself.
So:
 
NavigateUri="{Binding Path=.,  Converter ={StaticResource uriDictConverter}, ConverterParameter=UrlField}"

The converter will get the dictionary as input value and the Url attribute as ConverterParameter.
The converter should be something like (not tested):

 
public class UriDictionaryConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {

       IDictionary<string, object> dict = value asIDictionary<string, object>;
       String urlField = parameter as String;
       if (dict != null)
       {
           if (dict.ContainsKey(urlField))
              return  Uri("http://Myserver/" + dict[urlField]);
       }
             return null;
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
0 Kudos
dotMorten_esri
Esri Notable Contributor
One way to chain two converts is to route it through the datacontext.
<HyperLink DataContext="{Binding MyProperty, Converter={StaticResource Converter1}}"
NavigateUri={Binding Converter={StaticResource Converter2}}" />

That way NavigateUri will be binding to the value returned by MyProperty+Converter1, and route this through Converter2.
0 Kudos
Chula_VistaGIS
Occasional Contributor
One way to chain two converts is to route it through the datacontext.
<HyperLink DataContext="{Binding MyProperty, Converter={StaticResource Converter1}}"
NavigateUri={Binding Converter={StaticResource Converter2}}" />

That way NavigateUri will be binding to the value returned by MyProperty+Converter1, and route this through Converter2.


So, if I understand you correctly, I can use the DataContext property to submit my dictionary object to a dictionary converter.  The value of that dictionary object will then be submitted to my uriconverter ?

Thanks,
0 Kudos