How to respond to changes in data sources

Widgets often show information about a data source that is configured in the current operation view. Such widgets are known as data source consumers; most out-of-the-box widgets, such as the list, feature details, summary, and chart widgets are data source consumers.

To create a data source consumer widget, implement the IDataSourceConsumer interface, and in the OnRefresh method, add code that updates the widget UI with information.

The OnRefresh method provides an opportunity to perform some work when the data represented by a data source may have changed; for dynamic data sources, OnRefresh is called at the refresh interval, and for static data sources, OnRefresh is called once when the data source is initialized. For data sources that are based on a selection made in the map or a list, OnRefresh is also called when the selection changes. OnRefresh may also be called if a broken data source is repaired; see the Broken data sources section in the Working with data sources topic.

How to make a data source consumer widget

The following steps assume that a single data source is consumed. Note that the Widget item template adds most of this code by default.

  1. In the widget class, implement the IDataSourceConsumer interface.

    Implement IDataSourceConsumer interface

    public partial class MyWidget : UserControl, IWidget, IDataSourceConsumer
    

    Implement IDataSourceConsumer interface

    Public Class MyWidget
      Inherits UserControl
      Implements IWidget, IDataSourceConsumer
    
  2. Ensure an ExportMetadata attribute is present with the name DataSourceRequired and the value True. This ensures that if there are no data sources currently defined in the operation view, the widget will not be available in the Add Widget dialog box.

    DataSourceRequired attribution

    [ExportMetadata("DataSourceRequired", true)]
    

    DataSourceRequired attribution

    <ExportMetadata("DataSourceRequired", True)>
    
  3. From the DataSourceIds property, return the unique ID of the data source that the widget will consume, and ensure any IDs are saved by adding the DataMember attribute to the variable that stores those IDs.

    Implement DataSourceIds property

    [DataMember(Name = "dataSourceIds")]
    public string[] DataSourceIds
    {
      get; private set; 
    }
    

    Implement DataSourceIds property

    Private dsIds As String()
    
      <DataMember(Name:="dataSourceIds")>
      Public ReadOnly Property DataSourceIds As String() Implements IDataSourceConsumer.DataSourceIds
        Get
          Return dsIds
        End Get
      End Property
    
      Private WriteOnly Property SetDataSourceIds As String()
        Set(value As String())
          dsIds = value
        End Set
      End Property
    

    Typically the data source is chosen by the author of the operation view during widget configuration, and is set onto the widget class before the IWidget.Configure method returns, and therefore the data source consumer should provide appropriate private members to set this property as well.

  4. In the OnRefresh method, perform the main work of the widget, showing the required information taken from the consumed data source.

    Implement OnRefresh

    public void OnRefresh(DataSource dataSource)
    {
      DoQuery(dataSource);
    }
    
    private async void DoQuery(DataSource dataSource)
    {
      Query countQuery = new Query(string.Format("{0} > 0", dataSource.ObjectIdFieldName), new string[] { dataSource.ObjectIdFieldName });
      QueryResult result = await dataSource.ExecuteQueryStatisticAsync(Statistic.Count, countQuery);
      if ((!result.Canceled) && (result != null) && (result.Features != null) && (result.Features.Count == 1))
      {
        object val = result.Features[0].Attributes["Count"];
      // Do something with the result
      }
    }
    

    Implement OnRefresh

    Public Sub OnRefresh(dataSource As ESRI.ArcGIS.OperationsDashboard.DataSource) Implements IDataSourceConsumer.OnRefresh
      DoQuery(dataSource)
    End Sub
    
    Private Async Sub DoQuery(dataSource As ESRI.ArcGIS.OperationsDashboard.DataSource)
      Dim countQuery As Query = New Query(String.Format("{0} > 0", dataSource.ObjectIdFieldName), New String() {dataSource.ObjectIdFieldName})
      Dim result As QueryResult = Await dataSource.ExecuteQueryStatisticAsync(Statistic.Count, countQuery)
      If ((Not result.Canceled) AndAlso (Not result Is Nothing) AndAlso (Not result.Features Is Nothing) AndAlso (result.Features.Count = 1)) Then
        Dim val As Object = result.Features(0).Attributes("Count")
        ' Do something with the result
      End If
    End Sub
    

    Typically, the OnRefresh calls one of the async query methods on the DataSource class—ExecuteQueryAsync, ExecuteQueryStatisticAsync, or ExecuteQueryObjectIdsAsync. As these methods are async, they can be called from an async method, allowing the application to continue executing other work.

  5. In the OnRemove method, respond to a data source being removed by removing any stored references to the data source or its ID. The DataSourceIds property should return null at this point. If the data source against which a widget is configured is removed, the widget must then be re-configured with a valid data source in order for the widget to be operational again.

    Implement OnRemove

    public void OnRemove(DataSource dataSource)
    {
      DataSourceIds = new string[0];
    }
    

    Implement OnRemove

    Public Sub OnRemove(dataSource As ESRI.ArcGIS.OperationsDashboard.DataSource) Implements IDataSourceConsumer.OnRemove
      SetDataSourceIds = New String() {}
    End Sub
    

    OnRemove is also called when an operation view is closed; removing any values from the DataSourceIds property at this point does not affect the last state of this property that was persisted on the last save, and therefore the last saved DataSourceIds will be reinstated when the operation view is next reopened.

Consuming multiple data sources

As the DataSourceIds property allows a widget to return an array of data source IDs, it is possible to create a widget that consumes more than one data source. In this case, the OnRefresh method will be called for each data source that is consumed, receiving the different data sources as the incoming dataSource parameter in each separate method call.

1/27/2015