Version

ODataVirtualDataProvider

This topic provides implementation of ODataVirtualDataProvider that is required for using the ODataVirtualDataSource with the XamDataGrid™ control.

In C#:

public class ODataVirtualDataSourceDataProvider
       : IDataSourceVirtualDataProvider
{

    private ODataVirtualDataSourceDataProviderWorker _worker;
    private LinkedList<int> _requests = new LinkedList<int>();
    private DataSourcePageLoadedCallback _callback;

    public ODataVirtualDataSourceDataProvider()
    {
        _sortDescriptions = new SortDescriptionCollection();
        _sortDescriptions.CollectionChanged += SortDescriptions_CollectionChanged;
        _filterExpressions = new FilterExpressionCollection();
        _filterExpressions.CollectionChanged += FilterExpressions_CollectionChanged;
        _groupDescriptions = new SortDescriptionCollection();
        _groupDescriptions.CollectionChanged += GroupDescriptions_CollectionChanged;
        _summaryDescriptions = new SummaryDescriptionCollection();
        _summaryDescriptions.CollectionChanged += _summaryDescriptions_CollectionChanged;

    }

    private void _summaryDescriptions_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        QueueAutoRefresh();
    }

    private void FilterExpressions_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        QueueAutoRefresh();
    }

    private void SortDescriptions_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        QueueAutoRefresh();
    }

    private void GroupDescriptions_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        QueueAutoRefresh();
    }

    public void AddPageRequest(int pageIndex, DataSourcePageRequestPriority priority)
    {
        if (DeferAutoRefresh)
        {
            return;
        }

        if (_worker != null && _worker.IsShutdown)
        {
            _worker = null;
            _callback = null;
        }

        if (_worker == null)
        {
            CreateWorker();
        }

        if (priority == DataSourcePageRequestPriority.High)
        {
            _requests.AddFirst(pageIndex);
        }
        else
        {
            _requests.AddLast(pageIndex);
        }
        if (!_worker.AddPageRequest(pageIndex, priority))
        {
            _worker = null;
            _callback = null;
            AddPageRequest(pageIndex, priority);
        }
    }

    private void CreateWorker()
    {
        if (!Valid())
        {
            return;
        }

        _callback = RaisePageLoaded;

        var settings = GetWorkerSettings();

        _worker = new ODataVirtualDataSourceDataProviderWorker(settings);
    }

    private bool Valid()
    {
        return EntitySet != null &&
            BaseUri != null;
    }

    private ODataVirtualDataSourceDataProviderWorkerSettings GetWorkerSettings()
    {
        return new ODataVirtualDataSourceDataProviderWorkerSettings()
        {
            BaseUri = _baseUri,
            EntitySet = _entitySet,
            PageSizeRequested = _pageSizeRequested,
            TimeoutMilliseconds = _timeoutMilliseconds,
            PageLoaded = _callback,
            ExecutionContext = _executionContext,
            SortDescriptions = _sortDescriptions,
            FilterExpressions = _filterExpressions,
            PropertiesRequested = _propertiesRequested,
            GroupDescriptions = _groupDescriptions,
            IsAggregationSupportedByServer = _isAggregationSupportedByServer,
            SummaryDescriptions = _summaryDescriptions,
            SummaryScope = _summaryScope
        };
    }

    public void RemovePageRequest(int pageIndex)
    {
        _requests.Remove(pageIndex);
        if (_worker == null)
        {
            return;
        }
        _worker.RemovePageRequest(pageIndex);
    }

    public void RemoveAllPageRequests()
    {
        _requests.Clear();
        if (_worker == null)
        {
            return;
        }
        _worker.RemoveAllPageRequests();
    }

    public void Close()
    {
        if (_worker != null)
        {
            _worker.Shutdown();
            _worker = null;
            _callback = null;
        }
    }

    private DataSourcePageLoadedCallback _pageLoaded;
    public DataSourcePageLoadedCallback PageLoaded
    {
        get
        {
            return _pageLoaded;
        }
        set
        {
            _pageLoaded = value;
            QueueAutoRefresh();
        }
    }

    private void RaisePageLoaded(IDataSourcePage page, int fullCount, int actualPageSize)
    {
        if (_pageLoaded != null)
        {
            _currentFullCount = fullCount;
            if (_currentSchema == null)
            {
                IDataSourceSchema currentSchema = null;
                if (page != null)
                {
                    currentSchema = page.Schema();
                }

                _currentSchema = currentSchema;
                if (SchemaChanged != null)
                {
                    SchemaChanged(this, new DataSourceDataProviderSchemaChangedEventArgs(_currentSchema, _currentFullCount));
                }
            }

            if (page.PageIndex() != ODataVirtualDataSourceDataProviderWorker.SchemaRequestIndex)
            {
                _pageLoaded(page, fullCount, actualPageSize);
            }
        }
    }

    private void KillWorker()
    {
        if (_worker != null)
        {
            _worker.Shutdown();
            _worker = null;
            _callback = null;
        }
    }

    private int _pageSizeRequested = 50;
    public int PageSizeRequested
    {
        get
        {
            return _pageSizeRequested;
        }
        set
        {
            _pageSizeRequested = value;
            QueueAutoRefresh();
        }
    }

    private string _baseUri = null;
    public string BaseUri
    {
        get
        {
            return _baseUri;
        }
        set
        {
            var oldValue = _baseUri;
            _baseUri = value;
            if (oldValue != _baseUri)
            {
                QueueAutoRefresh();
                if (Valid() && DeferAutoRefresh)
                {
                    QueueSchemaFetch();
                }
            }
        }
    }

    private string _entitySet = null;
    public string EntitySet
    {
        get
        {
            return _entitySet;
        }
        set
        {
            var oldValue = _entitySet;
            _entitySet = value;
            if (oldValue != _entitySet)
            {
                QueueAutoRefresh();
                if (Valid() && DeferAutoRefresh)
                {
                    QueueSchemaFetch();
                }
            }
        }
    }

    private int _timeoutMilliseconds = 10000;
    public int TimeoutMilliseconds
    {
        get
        {
            return _timeoutMilliseconds;
        }
        set
        {
            _timeoutMilliseconds = value;
            QueueAutoRefresh();
        }
    }

    private bool _isAggregationSupportedByServer = false;
    /// <summary>
    /// Gets or sets whether the server supports aggregation query options required for grouping.
    /// </summary>
    public bool IsAggregationSupportedByServer
    {
        get
        {
            return _isAggregationSupportedByServer;
        }
        set
        {
            var oldValue = _isAggregationSupportedByServer;
            _isAggregationSupportedByServer = value;
            QueueAutoRefresh();
        }
    }

    public object GetItemValue(object item, string valueName)
    {
        var dic = (IDictionary<string, object>)item;
        if (dic.ContainsKey(valueName))
        {
            return dic[valueName];
        }
        else
        {
            return null;
        }
    }

    public event DataSourceDataProviderSchemaChangedHandler SchemaChanged;
    private int _currentFullCount = 0;
    private IDataSourceSchema _currentSchema;

    public int ActualCount
    {
        get
        {
            return _currentFullCount;
        }
    }

    public IDataSourceSchema ActualSchema
    {
        get
        {
            return _currentSchema;
        }
    }

    private IDataSourceExecutionContext _executionContext;
    public IDataSourceExecutionContext ExecutionContext
    {
        get
        {
            return _executionContext;
        }
        set
        {
            _executionContext = value;
            QueueAutoRefresh();
        }
    }

    private IDataSourceDataProviderUpdateNotifier _updateNotifier;
    public IDataSourceDataProviderUpdateNotifier UpdateNotifier
    {
        get
        {
            return _updateNotifier;
        }
        set
        {
            _updateNotifier = value;
        }
    }

    private bool _deferAutoRefresh = false;
    public bool DeferAutoRefresh
    {
        get
        {
            return _deferAutoRefresh;
        }

        set
        {
            _deferAutoRefresh = value;
            if (!_deferAutoRefresh)
            {
                QueueAutoRefresh();
            }
            if (_deferAutoRefresh && Valid() && _currentSchema == null)
            {
                QueueSchemaFetch();
            }
        }
    }

    public bool IsSortingSupported
    {
        get
        {
            return true;
        }
    }

    public bool IsFilteringSupported
    {
        get
        {
            return true;
        }
    }

    private SortDescriptionCollection _sortDescriptions;
    public SortDescriptionCollection SortDescriptions
    {
        get
        {
            return _sortDescriptions;
        }
    }

    private string[] _propertiesRequested;
    public string[] PropertiesRequested
    {
        get
        {
            return _propertiesRequested;
        }
        set
        {
            _propertiesRequested = value;
            QueueAutoRefresh();
        }
    }

    private FilterExpressionCollection _filterExpressions;
    public FilterExpressionCollection FilterExpressions
    {
        get
        {
            return _filterExpressions;
        }
    }

    public bool NotifyUsingSourceIndexes
    {
        get
        {
            return true;
        }
    }

    public bool IsItemIndexLookupSupported
    {
        get
        {
            return false;
        }
    }

    public bool IsKeyIndexLookupSupported
    {
        get
        {
            return false;
        }
    }

    public bool IsGroupingSupported
    {
        get
        {
            return false;
        }
    }

    private SortDescriptionCollection _groupDescriptions;
    public SortDescriptionCollection GroupDescriptions
    {
        get
        {
            return _groupDescriptions;
        }
    }

    private SummaryDescriptionCollection _summaryDescriptions;
    public SummaryDescriptionCollection SummaryDescriptions
    {
        get
        {
            return _summaryDescriptions;
        }
    }

    private DataSourceSummaryScope _summaryScope;
    public DataSourceSummaryScope SummaryScope
    {
        get
        {
            return _summaryScope;
        }
        set
        {
            _summaryScope = value;
        }
    }

    public void NotifySetItem(int index, object oldItem, object newItem)
    {
        if (UpdateNotifier != null)
        {
            UpdateNotifier.NotifySetItem(index, oldItem, newItem);
        }
    }

    public void NotifyClearItems()
    {
        if (UpdateNotifier != null)
        {
            UpdateNotifier.NotifyClearItems();
        }
    }

    public void NotifyInsertItem(int index, object newItem)
    {
        if (UpdateNotifier != null)
        {
            UpdateNotifier.NotifyInsertItem(index, newItem);
        }
    }

    public void NotifyRemoveItem(int index, object oldItem)
    {
        if (UpdateNotifier != null)
        {
            UpdateNotifier.NotifyRemoveItem(index, oldItem);
        }
    }

    internal bool _schemaFetchQueued = false;
    public void QueueSchemaFetch()
    {
        if (_schemaFetchQueued)
        {
            return;
        }

        if (ExecutionContext != null)
        {
            _schemaFetchQueued = true;
            ExecutionContext.EnqueueAction(DoSchemaFetchInternal);
        }
    }

    internal void DoSchemaFetchInternal()
    {
        if (!_schemaFetchQueued)
        {
            return;
        }
        _schemaFetchQueued = false;
        SchemaFetchInternal();
    }

    internal void SchemaFetchInternal()
    {
        SchemaFetchInternalOverride();
    }

    protected virtual void SchemaFetchInternalOverride()
    {
        if (!DeferAutoRefresh)
        {
            return;
        }
        RemoveAllPageRequests();
        KillWorker();
        CreateWorker();

        AddSchemaRequest();
    }

    private void AddSchemaRequest()
    {
        _worker.AddPageRequest(
            ODataVirtualDataSourceDataProviderWorker.SchemaRequestIndex,
            DataSourcePageRequestPriority.High
            );
    }

    internal bool _autoRefreshQueued = false;
    public void QueueAutoRefresh()
    {
        if (DeferAutoRefresh)
        {
            return;
        }
        if (_autoRefreshQueued)
        {
            return;
        }

        if (ExecutionContext != null)
        {
            _autoRefreshQueued = true;
            ExecutionContext.EnqueueAction(DoRefreshInternal);
        }
    }

    internal void DoRefreshInternal()
    {
        if (DeferAutoRefresh)
        {
            _autoRefreshQueued = false;
            return;
        }
        if (!_autoRefreshQueued)
        {
            return;
        }
        _autoRefreshQueued = false;
        RefreshInternal();
    }

    internal void RefreshInternal()
    {
        RefreshInternalOverride();
    }

    protected virtual void RefreshInternalOverride()
    {
        RemoveAllPageRequests();
        KillWorker();
        CreateWorker();
        //TODO: should we have this here? prob need to readd request for current page instead.
        _worker.AddPageRequest(0, DataSourcePageRequestPriority.Normal);
    }

    public void FlushAutoRefresh()
    {
        DoRefreshInternal();
    }

    public void Refresh()
    {
        RefreshInternal();
    }

    public int IndexOfItem(object item)
    {
        return -1;
    }

    public int IndexOfKey(object[] key)
    {
        return -1;
    }

	public DataSourceSchemaPropertyType ResolveSchemaPropertyType(string propertyPath)
	{
		var propertiesInPath = propertyPath.Split('.');
		if (propertiesInPath.Length == 1 && this.ActualSchema != null)
		{
			for (int i = 0; i < this.ActualSchema.PropertyNames.Length; i++)
			{
				if (this.ActualSchema.PropertyNames[i] == propertiesInPath[0])
				{
					return this.ActualSchema.PropertyTypes[i];
				}
			}
		}

		return DataSourceSchemaPropertyType.ObjectValue;
	}
}