/// <summary> /// Called when a ItemProxy should be displayed in the river. The method will attempt to get data for the item either from the /// river's data source or the history. If no data is available, the item will not be shown and no attempt will be made to show it /// until the next loop around the grid. /// </summary> /// <param name="proxy">The ItemProxy which should be added.</param> /// <param name="maintainOrientation">if set to <c>true</c> [maintain orientation].</param> /// <param name="maintainUnblockedData">if set to <c>true</c> [maintain unblocked data].</param> private void AttemptToAddToRiver(ItemProxy proxy, bool maintainOrientation, bool maintainUnblockedData) { RiverItemState state = GetState(proxy); if (state == null) { return; } if (state.DidAttemptToAddToRiver) { return; } RiverItemBase riverItem = proxy.FindVisualChild<RiverItemBase>(); double orientation = 0; bool isPortrait = state.RowSpan > state.ColumnSpan; if (riverItem == null) { orientation = isPortrait ? 90 : 0; } else { int page = (int)Math.Ceiling(_cumulativeScrollChange / (_totalColumns * GridCellSize.Width)); if (GetItemVisibilityInfo(state).IsLooping) { page++; } RiverItemHistoryInfo history = _history.Where(h => h.State == state && h.Grid == page).FirstOrDefault(); object data = null; if (history != null) { // Use the historical data and orientation if it exists. data = history.Data; orientation = history.Orientation; } else { data = riverItem.GetData(state, maintainUnblockedData); if (InteractiveSurface.PrimarySurfaceDevice.Tilt == Tilt.Horizontal) { // If running on a tabletop, randomly rotate the item. orientation = _random.NextDouble() > .5 ? 0 : 180; if (isPortrait) { // Rotate vertical items. orientation += 90 * (_random.NextDouble() > .5 ? 1 : -1); } if (state.RowSpan == state.ColumnSpan && _random.NextDouble() > .5) { // Maybe rotate square items. orientation += 90 * (_random.NextDouble() > .5 ? 1 : -1); } } else if (isPortrait) { // If running vertically, portrait items still get rotated to portrait. orientation = _random.NextDouble() > .5 ? 90 : -90; } else { // If running vertically and not portrait, always render right-side-up. orientation = 0; } history = new RiverItemHistoryInfo { State = state, Grid = page, Orientation = orientation }; _history.Add(history); } history.Data = riverItem.RenderData(state, data); if (history.Data == null) { // The item rejected this data and didn't provide new data. _history.Remove(history); } if (data == null) { // The item rejected the attempt to add, so don't try again until it's looped around. state.DidAttemptToAddToRiver = true; proxy.Visibility = Visibility.Collapsed; } } if (maintainOrientation) { // Don't apply the orientation if this was a user-requested refresh. return; } proxy.Orientation = state.OriginalOrientation = orientation; }
/// <summary> /// Contains the main logic for creating, destroying, and positioning items. This is called whenever the HorizontalOffset changes. /// </summary> /// <param name="proxy">The proxy to update.</param> /// <param name="state">The state of the proxy.</param> private void UpdateScrollPosition(ItemProxy proxy, RiverItemState state) { if (GridCellSize == Size.Empty || ActualWidth == 0 || ActualHeight == 0 || _totalColumns == 0 || _totalRows == 0) { // Not initialized yet. return; } if (state.IsRemovedFromRiver) { // This item is pulled from the river, so don't do anything with it. return; } // Get the pool for items of this style. Style proxyStyle = state.ProxyStyle; Queue<ItemProxy> pool = null; if (proxyStyle == null) { // There's no style, so use the default pool. pool = _defaultRiverItemPool; } else { // There is a style, so create a pool if needed, and use that. if (!_styledRiverItemPool.ContainsKey(proxyStyle)) { _styledRiverItemPool[proxyStyle] = new Queue<ItemProxy>(); } pool = _styledRiverItemPool[proxyStyle]; } RiverItemVisibilityInfo visibilityInfo = GetItemVisibilityInfo(state); if (!visibilityInfo.IsVisible) { if (proxy != null) { RiverItemBase riverItem = proxy.FindVisualChild<RiverItemBase>(); // This definition should not be visible, so hide it. state.IsAnimatingBackToRiver = false; state.IsAnimatingToContactOrientation = false; state.IsAnimatingToRemovedSize = false; state.DidAttemptToAddToRiver = false; state.IsRemovedFromRiver = false; _stateToProxyMap[state] = null; _sviToProxyMap.Remove(proxy); proxy.Visibility = Visibility.Hidden; if (riverItem != null) { riverItem.Cleanup(); } pool.Enqueue(proxy); } return; } // The definition should be visible, but it's not paired with any ItemProxy yet, so build or recycle one. if (proxy == null) { if (pool.Count > 0) { // Use an SVI from the queue. proxy = pool.Dequeue(); proxy.Visibility = Visibility.Visible; } else { // Set up a new proxy. proxy = AddNewItemProxy(); proxy.Style = proxyStyle; } // Size the ScatterView item when it's first added to the river. bool isPortrait = state.RowSpan > state.ColumnSpan; double itemWidth = state.ColumnSpan * GridCellSize.Width; double itemHeight = state.RowSpan * GridCellSize.Height; itemWidth += Plane.GetPlaneFrontPadding(proxy).Left + Plane.GetPlaneFrontPadding(proxy).Right; itemHeight += Plane.GetPlaneFrontPadding(proxy).Top + Plane.GetPlaneFrontPadding(proxy).Bottom; proxy.Width = isPortrait ? itemHeight : itemWidth; proxy.Height = isPortrait ? itemWidth : itemHeight; proxy.Visibility = Visibility.Visible; // More setup of added items. _stateToProxyMap[state] = proxy; _sviToProxyMap[proxy] = state; AttemptToAddToRiver(proxy, false, false); } if (state.DidAttemptToAddToRiver) { // We already tried to add this one and it rejected the add, so wait until it's looped around. return; } // Update the position of the item. proxy.Center = GetItemCenter(state); }