/// <summary> /// Called by the river when the item should retrieve data from its data source. /// </summary> /// <param name="state">A definition which describes the size and position of this item in the river.</param> /// <param name="maintainUnblockedData">if set to <c>true</c> [maintain unblocked data].</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal override object GetData(RiverItemState state, bool maintainUnblockedData) { if (DesignerProperties.GetIsInDesignMode(this)) { return(new object()); } else if (AppState.Instance.FeedProcessor != null) { if (maintainUnblockedData && _feedItem != null && _feedItem.BlockReason == BlockReason.None) { return(_feedItem); } FeedItem feedItem = null; if (state.RowSpan == state.ColumnSpan) { // If it's square, be an image. feedItem = AppState.Instance.FeedProcessor.GetNextItem(ContentType.Image); } else { // If not, be twitter or news. feedItem = AppState.Instance.FeedProcessor.GetNextItem(ContentType.Status | ContentType.News); } return(feedItem); } return(null); }
/// <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); }
/// <summary> /// Updates the grid layout of the river. /// </summary> private void UpdateGridLayout() { CompositionTarget.Rendering -= CompositionTarget_Rendering; if (GridLayout == null) { return; } Grid layout = GridLayout.LoadContent() as Grid; // Copy the chilren in the grid to another list for easy access. _states = new List<RiverItemState>(); _stateToProxyMap = new Dictionary<RiverItemState, ItemProxy>(); _sviToProxyMap = new Dictionary<ItemProxy, RiverItemState>(); foreach (UIElement child in layout.Children) { RiverItemState state = new RiverItemState { Row = Grid.GetRow(child), Column = Grid.GetColumn(child), RowSpan = Grid.GetRowSpan(child), ColumnSpan = Grid.GetColumnSpan(child), ProxyStyle = GetProxyStyle(child), ItemStyle = GetItemStyle(child), RemovedSize = Size.Empty }; _states.Add(state); _stateToProxyMap[state] = null; // Compute how many rows and columns have been specified. _totalRows = Math.Max(_totalRows, state.Row + state.RowSpan - 1); _totalColumns = Math.Max(_totalColumns, state.Column + state.ColumnSpan - 1); } _totalColumns++; _totalRows++; _scatterView.Items.Clear(); _styledRiverItemPool.Clear(); if (DesignerProperties.GetIsInDesignMode(this)) { Update(); return; } // Begin rendering. CompositionTarget.Rendering += CompositionTarget_Rendering; }
private void UpdateAnimatingBackToRiver(RiverItemState state) { ScatterViewItem svi = state.Svi; if (state.IsAnimatingBackToRiverComplete) { // When the animation is complete, return the item to the river. state.IsAnimatingBackToRiver = false; state.IsAnimatingBackToRiverComplete = false; state.IsRemovedFromRiver = false; state.Svi.IsHitTestVisible = true; state.RemovedSize = Size.Empty; state.Svi = null; _scatterView.Items.Remove(svi); _stateToProxyMap[state].Visibility = Visibility.Visible; UpdateScrollPosition(_stateToProxyMap[state], state); return; } Rect screen = new Rect(0, 0, Application.Current.MainWindow.ActualWidth, Application.Current.MainWindow.ActualHeight); double diagonal = (new Point(svi.ActualWidth, svi.ActualHeight) - new Point()).Length; screen.Inflate(new Size(diagonal, diagonal)); double currentTime = (DateTime.Now - state.AnimateBackBeginTime).TotalSeconds; // Determine the size to animate to. bool isPortrait = state.RowSpan > state.ColumnSpan; double itemWidth = state.ColumnSpan * GridCellSize.Width; double itemHeight = state.RowSpan * GridCellSize.Height; itemWidth += Plane.GetPlaneFrontPadding(svi).Left + Plane.GetPlaneFrontPadding(svi).Right; itemHeight += Plane.GetPlaneFrontPadding(svi).Top + Plane.GetPlaneFrontPadding(svi).Bottom; double targetWidth = isPortrait ? itemHeight : itemWidth; double targetHeight = isPortrait ? itemWidth : itemHeight; // Determine the orientation to animate to. double begin = state.AnimateBackFromOrientation % 360; double end = state.OriginalOrientation % 360; double change = end - begin; if (Math.Abs(change) > 180) { // Don't go the long way around. if (end < begin) { end += 360; } else { begin += 360; } } change = end - begin; double orientationTime = Math.Abs(change / OrientSpeed); // Determine the center to animate to. Point center = GetItemCenter(state); double scrollChange = state.ReturnHorizontalOffset - state.OriginalHorizontalOffset; if (center.X > ActualWidth && scrollChange > 0) { // The position looped around, so just go off-screen left. center.X = -diagonal; } else if (center.X < 0 && scrollChange < 0) { // The position looped around, so just go off-screen right. center.X = ActualWidth + diagonal; } double centerTime = (state.AnimateBackFromCenter - center).Length / ReturnToRiverSpeed; // The duration of the animation will be the duration of the orientation or center animations, whichever is longer. double totalTime = centerTime >= MinimumTransitionDuration.TotalSeconds || centerTime > orientationTime ? centerTime : orientationTime; totalTime = Math.Max(totalTime, MinimumTransitionDuration.TotalSeconds); // Update the orientation animation. if (currentTime < totalTime && Math.Abs(state.OriginalOrientation - svi.Orientation) > 1) { svi.Orientation = SineEaseOut(currentTime, begin, change, totalTime); } else { svi.Orientation = state.OriginalOrientation; } // Update the center animation. if (currentTime < totalTime && (svi.Center - center).Length > 1) { svi.Center = new Point( SineEaseOut(currentTime, state.AnimateBackFromCenter.X, center.X - state.AnimateBackFromCenter.X, totalTime), SineEaseOut(currentTime, state.AnimateBackFromCenter.Y, center.Y - state.AnimateBackFromCenter.Y, totalTime)); } else { svi.Center = center; } // Update the width animation. if (currentTime < totalTime && Math.Abs(targetWidth - svi.ActualWidth) > 1) { svi.Width = SineEaseOut(currentTime, state.AnimateBackFromSize.Width, targetWidth - state.AnimateBackFromSize.Width, totalTime); } else { svi.Width = targetWidth; } // Update the height animation. if (currentTime < totalTime && Math.Abs(targetHeight - svi.ActualHeight) > 1) { svi.Height = SineEaseOut(currentTime, state.AnimateBackFromSize.Height, targetHeight - state.AnimateBackFromSize.Height, totalTime); } else { svi.Height = targetHeight; } // If the item animated offscreen, just let it go. bool isOutsideScreen = !screen.Contains(svi.Center); if (isOutsideScreen) { svi.Orientation = state.OriginalOrientation; svi.Center = center; svi.Width = targetWidth; svi.Height = targetHeight; } state.IsAnimatingBackToRiverComplete = svi.Orientation == state.OriginalOrientation && svi.Center == center && svi.Width == targetWidth && svi.Height == targetHeight; }
/// <summary> /// Performs programmatic animation of an item to its removed size. /// </summary> /// <param name="state">The state of the SVI.</param> private void UpdateAnimatingToRemovedSize(RiverItemState state) { ScatterViewItem svi = state.Svi; Thickness padding = Plane.GetPlaneFrontPadding(svi); bool isPortrait = state.RowSpan > state.ColumnSpan; double itemWidth = state.ColumnSpan * GridCellSize.Width; double itemHeight = state.RowSpan * GridCellSize.Height; itemWidth += padding.Left + padding.Right; itemHeight += padding.Top + padding.Bottom; double beginWidth = isPortrait ? itemHeight : itemWidth; double beginHeight = isPortrait ? itemWidth : itemHeight; double endWidth = state.RemovedSize.Width; double endHeight = state.RemovedSize.Height; endWidth += Plane.GetPlaneFrontPadding(svi).Left + Plane.GetPlaneFrontPadding(svi).Right; endHeight += Plane.GetPlaneFrontPadding(svi).Top + Plane.GetPlaneFrontPadding(svi).Bottom; double currentTime = (DateTime.Now - state.AnimateToRemovedSizeBeginTime).TotalSeconds; double totalTime = MinimumTransitionDuration.TotalSeconds; if (currentTime < totalTime) { svi.Width = SineEaseOut(currentTime, beginWidth, endWidth - beginWidth, totalTime); svi.Height = SineEaseOut(currentTime, beginHeight, endHeight - beginHeight, totalTime); } else { svi.Width = endWidth; svi.Height = endHeight; svi.MinWidth = Math.Min(svi.ActualWidth, state.MinSize.Width + padding.Left + padding.Right); svi.MinHeight = Math.Min(svi.ActualHeight, state.MinSize.Height + padding.Top + padding.Bottom); svi.CanScale = true; state.IsAnimatingToRemovedSize = false; RiverItemBase riverItem = svi.FindVisualChild<RiverItemBase>(); if (riverItem != null) { riverItem.RemoveFinished(); } } state.AnimateBackFromSize = new Size(svi.ActualWidth, svi.ActualHeight); }
/// <summary> /// Update the position of items which are animating to match the orientation of their contact. /// </summary> /// <param name="state">The state of the SVI.</param> private void UpdateAnimatingToContactOrientation(RiverItemState state) { ScatterViewItem svi = state.Svi; double contactOrientation = state.ContactOrientation; double begin = state.AnimateBackFromOrientation % 360; double end = contactOrientation % 360; double change = end - begin; if (Math.Abs(change) > 180) { // Don't go the long way around. if (end < begin) { end += 360; } else { begin += 360; } } change = end - begin; double currentTime = (DateTime.Now - state.AnimateToContactOrientationBeginTime).TotalSeconds; double totalTime = Math.Max(MinimumTransitionDuration.TotalSeconds, Math.Abs(change / OrientSpeed)); if (currentTime < totalTime && Math.Abs(svi.Orientation - contactOrientation) > 1) { svi.Orientation = SineEaseOut(currentTime, begin, change, totalTime); } else { svi.Orientation = contactOrientation; svi.CanRotate = true; state.IsAnimatingToContactOrientation = false; UpdateManipulation(svi); BeginIdleTimeout(svi); } }
/// <summary> /// Called by the river when the item should render some data. /// </summary> /// <param name="state">A definition which describes the size and position of this item in the river.</param> /// <param name="data">The data that the river is requesting to be rendered. The item can override this and return different data if needed.</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal override object RenderData(RiverItemState state, object data) { UserControl visualState = null; object finalData = data; if (DesignerProperties.GetIsInDesignMode(this)) { if (state.RowSpan == state.ColumnSpan) { visualState = _smallImage; } else if (App.Random.NextDouble() > .5) { visualState = _smallNews; } else { visualState = _smallTweet; } } else if (AppState.Instance.IsInitialized) { _feedItem = data as FeedItem; if (_feedItem != null && _feedItem.BlockReason != BlockReason.None) { // This object is being rendered from history, but it got blocked since it was last displayed. Reject this content and get new content. finalData = _feedItem = GetData(state, false) as FeedItem; } if (_feedItem is ImageFeedItem) { // visualState = removed ? _largeImage as UserControl : _smallImage as UserControl; visualState = _smallImage as UserControl; } else if (_feedItem is NewsFeedItem) { // visualState = removed ? _largeNews as UserControl : _smallNews as UserControl; visualState = _smallNews as UserControl; } else if (_feedItem is StatusFeedItem) { // visualState = removed ? _largeTweet as UserControl : _smallTweet as UserControl; visualState = _smallTweet as UserControl; } DataContext = _feedItem; if (_feedItem is ImageFeedItem && _parentProxy != null) { // Disable the item while it's loading. _parentProxy.IsEnabled = _smallImage.Image.BitmapImage != null; } _banBtn.Visibility = _feedItem != null && !string.IsNullOrEmpty(_feedItem.Author) ? Visibility.Visible : Visibility.Hidden; } GoToState(visualState); if (_feedItem != null && DateTime.Now - _feedItem.Date <= Settings.Default.NewItemAlert) { // Show the "breaking" animation for new items. _breaking.Begin(this, Template, true); } return finalData; }
/// <summary> /// Called by the river when the item should retrieve data from its data source. /// </summary> /// <param name="state">The state.</param> /// <param name="maintainUnblockedData">if set to <c>true</c> [maintain unblocked data].</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal abstract object GetData(RiverItemState state, bool maintainUnblockedData);
/// <summary> /// Called by the river when the item should render some data. /// </summary> /// <param name="state">A definition which describes the size and position of this item in the river.</param> /// <param name="data">The data that the river is requesting to be rendered. The item can override this and return different data if needed.</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal override object RenderData(RiverItemState state, object data) { UserControl visualState = null; object finalData = data; if (DesignerProperties.GetIsInDesignMode(this)) { if (state.RowSpan == state.ColumnSpan) { visualState = _smallImage; } else if (App.Random.NextDouble() > .5) { visualState = _smallNews; } else { visualState = _smallTweet; } } else if (AppState.Instance.IsInitialized) { _feedItem = data as FeedItem; if (_feedItem != null && _feedItem.BlockReason != BlockReason.None) { // This object is being rendered from history, but it got blocked since it was last displayed. Reject this content and get new content. finalData = _feedItem = GetData(state, false) as FeedItem; } if (_feedItem is ImageFeedItem) { // visualState = removed ? _largeImage as UserControl : _smallImage as UserControl; visualState = _smallImage as UserControl; } else if (_feedItem is NewsFeedItem) { // visualState = removed ? _largeNews as UserControl : _smallNews as UserControl; visualState = _smallNews as UserControl; } else if (_feedItem is StatusFeedItem) { // visualState = removed ? _largeTweet as UserControl : _smallTweet as UserControl; visualState = _smallTweet as UserControl; } DataContext = _feedItem; if (Backside != null) { TagBack tag = Backside.FindVisualChild <TagBack>(); if (tag != null) { tag.DataContext = DataContext; if (_feedItem == null) { tag.TagName = string.Empty; } else { // Force mobile.twitter.com, because twitter doesn't redirect to the mobile site properly on Windows Mobile 6 devices tag.TagName = _feedItem.Uri.OriginalString.Replace("twitter.com", "mobile.twitter.com"); } } } } GoToState(visualState); return(finalData); }
/// <summary> /// Called by the river when the item should retrieve data from its data source. /// </summary> /// <param name="state">The state.</param> /// <param name="maintainUnblockedData">if set to <c>true</c> [maintain unblocked data].</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal override object GetData(RiverItemState state, bool maintainUnblockedData) { // Always returns null. Only RenderData is called for removed items. return(null); }
/// <summary> /// Called by the river when the item should render some data. /// </summary> /// <param name="state">A definition which describes the size and position of this item in the river.</param> /// <param name="data">The data that the river is requesting to be rendered. The item can override this and return different data if needed.</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal override object RenderData(RiverItemState state, object data) { UserControl visualState = null; object finalData = data; if (DesignerProperties.GetIsInDesignMode(this)) { if (state.RowSpan == state.ColumnSpan) { visualState = _smallImage; } else if (App.Random.NextDouble() > .5) { visualState = _smallNews; } else { visualState = _smallTweet; } } else if (AppState.Instance.IsInitialized) { _feedItem = data as FeedItem; if (_feedItem != null && _feedItem.BlockReason != BlockReason.None) { // This object is being rendered from history, but it got blocked since it was last displayed. Reject this content and get new content. finalData = _feedItem = GetData(state, false) as FeedItem; } if (_feedItem is ImageFeedItem) { // visualState = removed ? _largeImage as UserControl : _smallImage as UserControl; visualState = _smallImage as UserControl; } else if (_feedItem is NewsFeedItem) { // visualState = removed ? _largeNews as UserControl : _smallNews as UserControl; visualState = _smallNews as UserControl; } else if (_feedItem is StatusFeedItem) { // visualState = removed ? _largeTweet as UserControl : _smallTweet as UserControl; visualState = _smallTweet as UserControl; } DataContext = _feedItem; if (Backside != null) { TagBack tag = Backside.FindVisualChild<TagBack>(); if (tag != null) { tag.DataContext = DataContext; if (_feedItem == null) { tag.TagName = string.Empty; } else { // Force mobile.twitter.com, because twitter doesn't redirect to the mobile site properly on Windows Mobile 6 devices tag.TagName = _feedItem.Uri.OriginalString.Replace("twitter.com", "mobile.twitter.com"); } } } } GoToState(visualState); return finalData; }
/// <summary> /// Called by the river when the item should retrieve data from its data source. /// </summary> /// <param name="state">The state.</param> /// <param name="maintainUnblockedData">if set to <c>true</c> [maintain unblocked data].</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal override object GetData(RiverItemState state, bool maintainUnblockedData) { // Always returns null. Only RenderData is called for removed items. return null; }
/// <summary> /// Called by the river when the item should render some data. /// </summary> /// <param name="state">A definition which describes the size and position of this item in the river.</param> /// <param name="data">The data that the river is requesting to be rendered. The item can override this and return different data if needed.</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal override object RenderData(RiverItemState state, object data) { UserControl visualState = null; object finalData = data; if (DesignerProperties.GetIsInDesignMode(this)) { if (state.RowSpan == state.ColumnSpan) { visualState = _smallImage; } else if (App.Random.NextDouble() > .5) { visualState = _smallNews; } else { visualState = _smallTweet; } } else if (AppState.Instance.IsInitialized) { _feedItem = data as FeedItem; if (_feedItem != null && _feedItem.BlockReason != BlockReason.None) { // This object is being rendered from history, but it got blocked since it was last displayed. Reject this content and get new content. finalData = _feedItem = GetData(state, false) as FeedItem; } if (_feedItem is ImageFeedItem) { // visualState = removed ? _largeImage as UserControl : _smallImage as UserControl; visualState = _smallImage as UserControl; } else if (_feedItem is NewsFeedItem) { // visualState = removed ? _largeNews as UserControl : _smallNews as UserControl; visualState = _smallNews as UserControl; } else if (_feedItem is StatusFeedItem) { // visualState = removed ? _largeTweet as UserControl : _smallTweet as UserControl; visualState = _smallTweet as UserControl; } DataContext = _feedItem; if (_feedItem is ImageFeedItem && _parentProxy != null) { // Disable the item while it's loading. _parentProxy.IsEnabled = _smallImage.Image.BitmapImage != null; } _banBtn.Visibility = _feedItem != null && !string.IsNullOrEmpty(_feedItem.Author) ? Visibility.Visible : Visibility.Hidden; } GoToState(visualState); if (_feedItem != null && DateTime.Now - _feedItem.Date <= Settings.Default.NewItemAlert) { // Show the "breaking" animation for new items. _breaking.Begin(this, Template, true); } return(finalData); }
/// <summary> /// Determines whether the item is visible given the current river position. /// </summary> /// <param name="state">The river item.</param> /// <returns>The ItemVisibilityInfo.</returns> private RiverItemVisibilityInfo GetItemVisibilityInfo(RiverItemState state) { double leftColumn = HorizontalOffset / GridCellSize.Width; // Determine if the item is visible given the current river position. bool isVisible = state.Column + state.ColumnSpan >= leftColumn && state.Column <= leftColumn + _screenColumns; // Whether or not this item is displaying past the end of the river, and looping around. bool isLooping = false; if (!isVisible && leftColumn + _screenColumns > _totalColumns) { // If this item is being displayed after the end of the river, do a different comparison to see if it's visible. int column = _totalColumns + state.Column; isVisible = column + state.ColumnSpan >= leftColumn && column <= leftColumn + _screenColumns; if (isVisible) { // If it's visible, set a flag to position it differently later. isLooping = true; } } return new RiverItemVisibilityInfo { IsLooping = isLooping, IsVisible = isVisible }; }
/// <summary> /// Given an item definition, return the center of that item for the current HorizontalOffset. /// </summary> /// <param name="state">The river item.</param> /// <returns>The center of the river item.</returns> private Point GetItemCenter(RiverItemState state) { double leftColumn = HorizontalOffset / GridCellSize.Width; // Naive left position. double left = (state.Column * GridCellSize.Width) - (leftColumn * GridCellSize.Width); if (GetItemVisibilityInfo(state).IsLooping) { // Left position when looping. left += _totalColumns * GridCellSize.Width; } // Shift to center. left += (state.ColumnSpan * GridCellSize.Width) / 2; // Naive top position. double top = state.Row * GridCellSize.Height; // Shift to center. top += (state.RowSpan * GridCellSize.Height) / 2; // Shift so that the whole river is centered vertically. top += (ActualHeight - (_totalRows * GridCellSize.Height)) / 2; return new Point(left, top); }
/// <summary> /// Called by the river when the item should render some data. /// </summary> /// <param name="state">The state.</param> /// <param name="data">The data that the river is requesting to be rendered. The item can override this and return different data if needed.</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal abstract object RenderData(RiverItemState state, object data);
/// <summary> /// Called by the river when the item should retrieve data from its data source. /// </summary> /// <param name="state">A definition which describes the size and position of this item in the river.</param> /// <param name="maintainUnblockedData">if set to <c>true</c> [maintain unblocked data].</param> /// <returns> /// The data that this item will render. If null, the item won't be shown. /// </returns> internal override object GetData(RiverItemState state, bool maintainUnblockedData) { if (DesignerProperties.GetIsInDesignMode(this)) { return new object(); } else if (AppState.Instance.FeedProcessor != null) { if (maintainUnblockedData && _feedItem != null && _feedItem.BlockReason == BlockReason.None) { return _feedItem; } FeedItem feedItem = null; if (state.RowSpan == state.ColumnSpan) { // If it's square, be an image. feedItem = AppState.Instance.FeedProcessor.GetNextItem(ContentType.Image); } else { // If not, be twitter or news. feedItem = AppState.Instance.FeedProcessor.GetNextItem(ContentType.Status | ContentType.News); } return feedItem; } return null; }