public override void MoveMasterRecord(TMasterDetailLink[] masterDetailLinks, TSplitLink splitLink)
        {
            //Here we need to modify FilteredData to contain only those records on FilteredData that are visible on this state.
            //If we created indexes on this method constructor's, this can be done fast.

            //on this example, as always, we will use a very slow method. The idea of this demo is not to demostrate how to do efficient code
            // (you probably have efficient methods on the bussines objects you are wrapping), but how to override the methods.

            if (FilteredData == null)
            {
                return;                        //this dataset is not on master-detail relationship and does not have any split relationship either.
            }
            FilteredData.Clear();
            int[] ChildColumn = new int[masterDetailLinks.Length];
            for (int i = 0; i < masterDetailLinks.Length; i++)
            {
                ChildColumn[i] = TableData.GetColumn(masterDetailLinks[i].ChildFieldName);
            }

            int SplitPos = 0;
            int StartRow = 0;

            if (splitLink != null)
            {
                StartRow = splitLink.SplitCount * splitLink.ParentDataSource.Position;
            }

            for (int r = 0; r < SortedData.Length; r++)
            {
                object[] Row        = SortedData[r];
                bool     RowApplies = true;
                for (int i = 0; i < masterDetailLinks.Length; i++)
                {
                    object key = masterDetailLinks[i].ParentDataSource.GetValue(masterDetailLinks[i].ParentField);
                    if (Convert.ToString(Row[ChildColumn[i]]) != Convert.ToString(key))
                    {
                        RowApplies = false;
                        break;
                    }
                }

                if (!RowApplies)
                {
                    continue;              //the row does not fit this master detail relationship.
                }
                SplitPos++;
                if (SplitPos <= StartRow)
                {
                    continue;                       //we are not filling the correct split slot.
                }
                FilteredData.Add(Row);
                if (splitLink != null && FilteredData.Count >= splitLink.SplitCount)
                {
                    return;
                }
            }
        }
 public override VirtualDataTableState CreateState(string sort, TMasterDetailLink[] masterDetailLinks, TSplitLink splitLink)
 {
     return(new SimpleVirtualArrayDataSourceState(this));
 }
        public ComplexVirtualArrayDataSourceState(ComplexVirtualArrayDataSource aTableData, string sort, TMasterDetailLink[] masterDetailLinks, TSplitLink splitLink)
            : base(aTableData)
        {
            if (sort == null || sort.Trim().Length == 0)
            {
                SortedData = aTableData.Data; //no need to clone, this is invariant.
            }
            else
            {
                SortedData = (object[][])aTableData.Data.Clone();
                int sortcolumn = aTableData.GetColumn(sort);
                if (sortcolumn < 0)
                {
                    throw new Exception("Can not find column \"" + sort + "\" in dataset \"" + TableName);
                }
                Array.Sort(SortedData, new ArrayComparer(sortcolumn));
            }


            //here we should use the data in masterdetaillinks and splitlink to create indexes to make the FilteredrowCount and MoveMasterRecord methods faster.
            //on this demo we are not going to do it.
            if ((masterDetailLinks != null && masterDetailLinks.Length > 0) || splitLink != null)
            {
                FilteredData = new List <object[]>();
            }
        }