Select to view content in your preferred language

Another relate editing post:

4214
17
Jump to solution
05-29-2012 04:11 PM
NathalieNeagle
Regular Contributor
Like a few others I'm trying to set up a relate and I want to be able to add records (rows) to my related table and change attribute infomation...basic editing.  There are a few post and Jennifer and Chris (ESRI) give suggestion(s) to start with the relate example and make the related table a feature services.  I've done both of these tasks but I've been having problems with figurin out how to move forward from this point.  I'm thinking I might have to convert the DataGrid that the example uses to a featuredatagrid.  Would this be the right move? I've tired thi with no success and was hoping for a push forward with some more insight or code.

Thanks
Nathalie


http://forums.arcgis.com/threads/47597-editing-related-table?highlight=related+records
http://forums.arcgis.com/threads/35452-Web-Editing-FeatureClass-with-Relatio
0 Kudos
17 Replies
NathalieNeagle
Regular Contributor
If try pair the FDG - Highlight in Red


        void QueryTask_ExecuteRelationshipQueryCompleted(object sender, RelationshipEventArgs e)
        {

            IEnumerable<Graphic> graphics = e.Result.RelatedRecordsGroup.First().Value;
            

              

          
             RelationshipResult pr = e.Result;
             if (pr.RelatedRecordsGroup.Count == 0)
             {

                 RelatedRowsDataGrid.ItemsSource = null;
             }
             else
             {
                 foreach (var pair in pr.RelatedRecordsGroup)
                 {

                     RelatedRowsDataGrid.ItemsSource = pair.Value;
                     MyFDG.ItemsSource = pair.Value;
                     

                 }
             }
        }



The featuredatagrid gets populated with the correct number of records but the fields seem like they are the geometry fields (Geometry, Symbol, MapTip, Selected, Dispatcher, etc --see attachement) not the attributes fields.


This was and has been the deal since the beginning

Thanks
Nathalie
0 Kudos
JoeHershman
MVP Alum
What is happening there is that you are binding the FDG to an IEnumerable<Graphic> so you are seeing all the properties on a Graphic object.  Try this (not sure it will work, but I think it might)

            foreach ( var pair in pr.RelatedRecordsGroup )
            {
                MyFDG.ItemsSource = pair.Value.Select(g => g.Attributes);
            }


That Selects the IEnumerable<Graphic> into an IEnumerable<IDictionary<string, object>>, basically an enumerator of Attributes

Good luck
Thanks,
-Joe
0 Kudos
NathalieNeagle
Regular Contributor
Joe,

Thanks again so much for sticking with this...very kind of you!

So your line of code  is throwing an error that states: �??System.Reflection.AmbiguousMatchException: Amiguous match found.�?�

The stack trace is really not telling me anything �?? see attachment

Not sure what's wrong.
0 Kudos
JoeHershman
MVP Alum
Sorry, when I looked at that later I see it would not work but we don't want to be using ItemsSource with the FeatureDataGrid, that is there because it inherits from DataGrid but really should be working with the GraphicsLayer property as the binding property.

You said you had it working to load the entire FeatureLayer data using code the Jenifer provided.  If you go back to that setup than the only part missing is filtering the list after the relationship query.  In that setup you have a class level variable l which is the FeatiureLayer.  I am going to call that _featureLayer because I hate having a variable named l.

Right now you have

        private void QueryTask_ExecuteRelationshipQueryCompleted(object sender, RelationshipEventArgs e)         {               IEnumerable<Graphic> graphics = e.Result.RelatedRecordsGroup.First().Value;                RelationshipResult pr = e.Result;              if (pr.RelatedRecordsGroup.Count == 0)              {                    RelatedRowsDataGrid.ItemsSource = null;              }              else              {                  foreach (var pair in pr.RelatedRecordsGroup)                  {                        RelatedRowsDataGrid.ItemsSource = pair.Value;                      MyFDG.ItemsSource = pair.Value;                                          }              }         }


What needs to happen in the RelationshipComplete handler is that the FeatureLayer (_featureLayer) gets filtered to only show the correct records.

        private void QueryTask_ExecuteRelationshipQueryCompleted(object sender, RelationshipEventArgs e)         {             //This line gets you the all features returned from the Relationship Query             IEnumerable<Graphic> graphics = e.Result.RelatedRecordsGroup.First().Value;                          // There are two ways to filter either using Where clause or using the ObjectIDs property             // before you set the Where clause to return all records 1=1 I think             // Here instead lets use the ObjectIDs approach, first get rid of the old Where                    _featureLayer.Where = null //remember _featureLayer is l                                      //ObjectIDs takes an int[] and with a little Linq we can get that array             // I am assumning you have included OBJECTID in your outfields when you defined the query                          int[] objectIds = graphics.Select(g => (int)g.Attributes["OBJECTID"]).ToArray();               //now set the ObjectIDs on our FeatureLayer                          _featureLayer.ObjectIDs = objectIds;               //Update the FeatureLayer to 'redraw' the new filtered set of Features                     _featureLayer.Update();               //And I hope this worked.  you could rebind the layer to the grid to make sure all is good             MyFDG.GraphicsLayer = _featureLayer;           }



Hope that helps
-Joe
Thanks,
-Joe
0 Kudos
NathalieNeagle
Regular Contributor
Joe,

Thanks for the post and the time.   The codes populating but I haven't had anytime to look at it....I'm going to spend sometime next week and I'll let you know....Hopefully I can mark this question as answered and give you some real credit.

Thanks again and have a good weekend.

Nathalie
0 Kudos
NathalieNeagle
Regular Contributor
Thanks Joe and Jennifer,

I finally got it working...now I just need to tweak it slightly to look good in my app and I want to add a delete button to delete a related record.  Thanks for all the time.

Nathalie
0 Kudos
NathalieNeagle
Regular Contributor
Joe and Jennifer

I know the conference is right around the corner (next week) and you are both probably slammed and getting ready for SD but I was wondering if you could help me out with the two small other items I can't seem to get:

First one is in the example http://resources.arcgis.com/en/help/silverlight-api/samples/start.htm#QueryRelatedRecords and in my (our I should say yours and Jennifer's). The linking ID usually the OBJECTID in the examples is displayed in the treeveiw when an item is selected.

   

  <!-- RELATED LINK RESOURCE-->
            <common:HierarchicalDataTemplate x:Key="TreeViewItemTemplate">
               <StackPanel Orientation="Horizontal" Margin="0">
                    <!--<Ellipse Fill="Transparent" Height="6" Width="6" StrokeThickness="2" Stroke="Black" Margin="0,0,10,0"/>-->
                    <!--<TextBlock Text="FeatureID:  " HorizontalAlignment="Left" FontSize="10" Margin="0"/>-->
                <TextBlock x:Name="TextBlockRelate" Text="{Binding Attributes[APN]}" HorizontalAlignment="Left" FontSize="10"/>
               
                </StackPanel>
            </common:HierarchicalDataTemplate>
            <!--END RELATED LINK RESOURCE-->





  <basics:TreeView x:Name="SelectedWellsTreeView" MaxHeight="180"  Grid.Column="0"  Margin="1"
                                 ItemsSource="{Binding}" BorderBrush="Gray" BorderThickness=".5"
                  SelectedItemChanged="SelectedWellsTreeView_SelectedItemChanged" 
                                 ItemTemplate="{StaticResource TreeViewItemTemplate}"
                                             
                                             
                            />
                                   



I want to take this ID but I'm not using the OBJECTID and pass or bind it back to my C# page to fill in the field of the newly added record. So when the Add button is click (Jennifer's code) the right ID is prepopulated for my enduser: I tried to bind and pass every which way and just can't get it.

   private void addrowButton_Click(object sender, RoutedEventArgs e)
        {
            var g = new Graphic();
            if (l != null && l.LayerInfo != null && l.LayerInfo.Fields != null)
            {
                foreach (var f in l.LayerInfo.Fields)
                {
                    g.Attributes[f.Name] = null;
                  //   g.Attributes["APN"] = RelateIdTextBlock.Text;
      //   g.Attributes["APN"] = SelectedWellsTreeView.SelectedValue.ToString());
                }
            }
            else
            {
                //g.Attributes["sf_311_serviceoid"] = 21467;
                //g.Attributes["agree_with_incident"] = (Int16)1;
                //g.Attributes["DateTime"] = DateTime.UtcNow;
                //g.Attributes["cient_ip"] = "unknown";
                //g.Attributes["notes"] = string.Format("Added - {0} - local time", DateTime.Now);
               // g.Attributes["APN"] = 2146700000;
                //g.Attributes["GEN_PLAN"] = "GPk";

            }
            l.Graphics.Add(g);
        }




My other questions is what about deleting a selected related record from the featuretablegrid.

Thanks
Nat
0 Kudos
JoeHershman
MVP Alum
How I have it setup which you would have to do slightly different (but pretty similar) is have a private field to hold the relationship id (in my case OID) so in my ExecuteComplete of the spatial query


        //The OID of the current related feature that the user selected
        private int _currentLocationId;

        private void SpatialQueryCompleted(object sender, QueryEventArgs e)
        {
            if ( e.FeatureSet.Features.Count() == 0 ) return;


            Graphic graphic = e.FeatureSet.Features[0];


            //Assign the location OID to internal field so can use when a new record is created
            _currentLocationId = Convert.ToInt32(graphic.Attributes["OBJECTID"]);


            RelationshipParameter parameter = new RelationshipParameter
                                                  {
                                                      ObjectIds = new[] { _currentLocationId },
                                                      RelationshipId = 0,
                                                      OutFields = new[] { "OBJECTID" }
                                                  };




            _queryTask.ExecuteRelationshipQueryCompleted += RelationshipQueryCompleted;
            _queryTask.ExecuteRelationshipQueryAsync(parameter);
        }



Then in the code where a new record is added


        private void ExecuteAdd()
        {
            //Create the new Graphic object and set the default values for the attributes
            Graphic graphic = new Graphic();
...
            graphic.Attributes.Add("LOCATION_OID", _currentLocationId);


            _featureLayer.Graphics.Add(graphic);


            //Set the bound GraphicsSource so the DataForm is loaded with the new record
            GraphicSource = graphic;
        }



in your case you would set the _currentLocationId to the attribute that you are using but other than that it is about the same.  What I also do is not include that relationship field in the OutFields on the FeatureLayer, so while I am setting it and creating the relationship the user does not see it

For a delete, I have not done this, but I think you would need to add a Delete button like the Add button and Remove from the FeatureLayer.  Maybe something along these lines


        private void DeleteButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            _featureLayer.Graphics.Remove(MyFeatureDataGrid.SelectedGraphics[0]);
        } 

Thanks,
-Joe
0 Kudos