Binding search result from FindTask to ListBox using DataTemplate SL4

4459
13
03-07-2011 10:06 AM
MariaFernandez
New Contributor
Hi, I am trying to bind the FindTask result to a listbox with ItemTemplate defined as a StaticResource (DataTemplate).
I got error:
Unable to cast object of type 'System.Windows.Data.Binding' to type 'System.Collections.IEnumerable'

Thanks!!
0 Kudos
13 Replies
DominiqueBroux
Esri Frequent Contributor
How looks your binding?
0 Kudos
MariaFernandez
New Contributor
I have this control in the mainpage.xaml
<ListBox x:Name="SearchListBox" Background="White"
                                         ItemsSource="{Binding}"
                                         ItemTemplate="{StaticResource FeatureDataTemplate}"
                                         VerticalAlignment="Top">
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"  />
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
            </ListBox>

The resource defined in the same page  is
<ItemsPanelTemplate x:Key="ItemsPanelTemplate1">
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>

I have a class Feature.vb
and a DataTemplate

<DataTemplate x:Key="FeatureDataTemplate">
        <Grid Width="auto">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="85"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
              
            </Grid.ColumnDefinitions>
           <Border BorderThickness="3" BorderBrush="Green" Grid.RowSpan="2" Grid.Column="0" >
                <Image Source="{Binding PhotoUri}" Stretch="Fill"   />
            </Border>

            <dataInput:Label Content="{Binding FeatureLayerName}" Grid.Row="0" Grid.Column="1"/>
            <dataInput:Label Content="{Binding FeatureLayerItemCount}" Grid.Row="1" Grid.Column="1"/>
         
                    
            <ListBox  Padding="2" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
                     ItemsSource ="{Binding Path=FeatureItems}"
                     ItemTemplate="{StaticResource FeatureItemDataTemplate}"
                     
                      />

          
        </Grid>
    </DataTemplate>
   
  
    <DataTemplate x:Key="FeatureItemDataTemplate">
        <Grid >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="100"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions >
                <RowDefinition ></RowDefinition>
                <RowDefinition ></RowDefinition>
            </Grid.RowDefinitions>
            <sdk:Label x:Name="labelName" Content="Name:" Grid.Column="0" Grid.Row="0"/>
            <dataInput:Label Content="{Binding Path=Name}" Grid.Row="0" Grid.Column="1"/>

            <sdk:Label x:Name="labelOwner" Content="Owner:" Grid.Column="0" Grid.Row="1"/>
            <dataInput:Label Content="{Binding Path=Owner}" Grid.Row="1" Grid.Column="1"/>

        </Grid>
    </DataTemplate>


In the executebutton click handling the FindTask I have:
SearchListBox.SetBinding(ListBox.ItemsSourceProperty, resultFeaturesBinding)
I am missing a way to assign the resultFeaturesBindeing to the getData in the Feature class (I don't know how to doit.)
Something like: 
Dim features = Feature.GetData(resultFeaturesBinding)
   Me.DataContext = features


Thanks for your help!!
0 Kudos
DominiqueBroux
Esri Frequent Contributor
At this time, I don't understand why you have 2 levels of listbox : one in your SearchListBox and one in your FeatureDataTemplate.

Let's focus on the first level. The goal is to initialize the 'ItemsSource' of your SearchListBox with an Enumeration of something.
It turns out out that the 'FindResults' returned by the 'FindTask' is a List of 'FindResult', so it's a good candidate as an ItemsSource.

To use it, there are 2 ways:
- Hook up an handler to the ExecuteCompleted event and, in the handler, initialize the DataContext of your control with e.FindResults (that's probably the easier way).

or - Set a binding by code to the LastResult property of the FindTask. The sample is working this way by this code:
           Binding resultFeaturesBinding = new Binding("LastResult");
            resultFeaturesBinding.Source = findTask;
            FindDetailsDataGrid.SetBinding(DataGrid.ItemsSourceProperty, resultFeaturesBinding); 
.Then in your FeatureDataTemplate you can use properties of a 'FindResult' (i.e. LayerName, LayerId, Feature, Value, ...)

So your XAML code
<Border BorderThickness="3" BorderBrush="Green" Grid.RowSpan="2" Grid.Column="0" >
<Image Source="{Binding PhotoUri}" Stretch="Fill" />
</Border>
 
<dataInput:Label Content="{Binding FeatureLayerName}" Grid.Row="0" Grid.Column="1"/>
<dataInput:Label Content="{Binding FeatureLayerItemCount}" Grid.Row="1" Grid.Column="1"/>
 
 
<ListBox Padding="2" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
ItemsSource ="{Binding Path=FeatureItems}"
ItemTemplate="{StaticResource FeatureItemDataTemplate}" 
 
/>
 
 


should rather be (since I don't see where FeatureLayerName, FeatreLayerItemCount and PhotoUri are coming from) :
<Border BorderThickness="3" BorderBrush="Green" Grid.RowSpan="2" Grid.Column="0" >
<Image Source="{Binding Feature.Attributes[PhotoUri]}" Stretch="Fill" />
</Border>
 
<dataInput:Label Content="{Binding LayerName}" Grid.Row="0" Grid.Column="1"/>
<dataInput:Label Content="{Binding LayerId}" Grid.Row="1" Grid.Column="1"/>
<dataInput:Label Content="{Binding Value}" Grid.Row="1" Grid.Column="1"/>
 


Hope this help.
0 Kudos
MariaFernandez
New Contributor
Thanks for your help!!!
I used your first suggestion and is working!!!!:
- Hook up an handler to the ExecuteCompleted event and, in the handler, initialize the DataContext of your control with e.FindResults (that's probably the easier way).

I passed the e.FindREsults to the getData function in the feature class and the double list is populated.
I used:

Public Shared Function GetData(ByVal data As Object) As IEnumerable(Of Feature)
        Dim list As New List(Of Feature)

        'list.Add(New Feature With {._featureLayerName = "FeatureLayerName1", ._featureLayerItemCount = "5 feature(s) found"})

        'list(0)._featureItems.Add(New FeatureItem With {.Name = "1FeatureItemName1", .Owner = "FeatureItemOwner"})
        'list(0)._featureItems.Add(New FeatureItem With {.Name = "2FeatureItemName2", .Owner = "FeatureItemOwner"})
        'list(0)._featureItems.Add(New FeatureItem With {.Name = "3FeatureItemName3", .Owner = "FeatureItemOwner"})
        'list(0)._featureItems.Add(New FeatureItem With {.Name = "4FeatureItemName4", .Owner = "FeatureItemOwner"})
        'list(0)._featureItems.Add(New FeatureItem With {.Name = "5FeatureItemName5", .Owner = "FeatureItemOwner"})

        Dim i As Integer = -1
        Dim CurrentLayer As String = ""
        For Each elem As ESRI.ArcGIS.Client.Tasks.FindResult In data
            If String.Compare(CurrentLayer, elem.LayerName, System.StringComparison.OrdinalIgnoreCase) <> 0 Then
                list.Add(New Feature With {._featureLayerName = elem.LayerName, ._featureLayerItemCount = "5 feature(s) found"})
                CurrentLayer = elem.LayerName
                i = i + 1
            End If

            list(i)._featureItems.Add(New FeatureItem With {.Name = elem.DisplayFieldName, .Owner = elem.Value})


        Next
Return list
    End Function

Now I got the list almost as I like it.
I need specifics fields from the layer instead what I am getting is the fields that have the information searched.
Also I need functionalities when mouse over the list item to displaythe feaures it in the map. How I could do that? I had this working using the grid.

THanks a lot for your help!!!!
Maria
0 Kudos
MariaFernandez
New Contributor
Additionally to this,
How we can search only in the visible layers?
Instead of
findParameters.LayerIds.AddRange(New Integer() {0, 1, 2, 3})

search in the visible only.

Thanks!!!!
0 Kudos
DominiqueBroux
Esri Frequent Contributor
I need specifics fields from the layer instead what I am getting is the fields that have the information searched.

The FindResult object contains a feature object with all its attributes. So you can extend your FeatureItem to store other attributes:
     .OtherAttribute = .elem.Feature.Attributes["AttributeName"]

or even to store the whole Feature:
.Feature= .elem.Feature

Also I need functionalities when mouse over the list item to display the feaures it in the map. How I could do that?

That will be easier if you store the Feature in your FeatureItem. So (as in the sample) from the SelectedItem, you can retrieve the Feature and show it in a graphics layer.
0 Kudos
Asgharkhan
Occasional Contributor

@Dominique i want this binding behind C#

How to?

<slData:DataGridTextColumn Binding="{Binding Attributes[FID]}" Header="النتائج" />

0 Kudos
DominiqueBroux
Esri Frequent Contributor

This thread Defining Results Datagrid In Code behind should help.



0 Kudos
MariaFernandez
New Contributor
Thanks a lot!!
Using the Feature.Attributes I got the info I needed:

list(i)._featureItems.Add(New FeatureItem With {.Name = elem.Feature.Attributes("NAME").ToString, .Owner = elem.Feature.Attributes("OWNER").ToString})
            list(i)._featureLayerItemCount = ItemLayerCounter.ToString & " feature(s) found"

Thanks!!

I also need the legend dymbol for the layer. The image I have in the feature class is to store the legend symbol for the layer. How we can access that information?

Thank you very much for all your help!!!
0 Kudos