Snapshot not generated for the web browser control

Aug 23, 2011 at 11:59 AM

The content tab does not show any snapshot of the web browser control in the tabitem. Since most of my tab space is occupied by a web browser control the content tab previews and tool tip previews would be useless for me if it doesn't show any preview for the web browser control.

Coordinator
Aug 23, 2011 at 12:13 PM

Futurix,

Have a look at this discussion: http://fabtab.codeplex.com/discussions/81067

Long story short, it can be done via GDI, but you will have to add it into the FabTab source yourself, since that is not a scenario that I will be supporting.  I give a code snippet though that shows how it would be done.

Josh

Aug 24, 2011 at 4:24 AM

Hey Josh

Thanks for the quick reply. Looking into the solution mentioned at http://fabtab.codeplex.com/discussions/81067. Will let you know how it turns out.

Thanks

 - Futurix

Aug 24, 2011 at 8:40 AM

Modified the CreateBitmap method of the BitmapSourceBuilder of latest changeset to use GDI.

 internal BitmapSource CreateBitmap(FrameworkElement element)
        {
            if (element == null)
                return null;

            ForceRenderIfElementIsInsideAHiddenListView(element);

            DrawingVisual visual;
            int w;
            int h;

            GetInformationForRenderTargetBitmap(element, out visual, out w, out h);

            if (w == 0 || h == 0)
                return null;

	    System.Windows.Point p0 = visual.PointToScreen(visual.DescendantBounds.TopLeft);
	    System.Drawing.Point p1 = new System.Drawing.Point((int)p0.X, (int)p0.Y);
	    System.Drawing.Bitmap image = new System.Drawing.Bitmap((int)w, (int)h);
	    System.Drawing.Graphics imgGraphics = System.Drawing.Graphics.FromImage(image);
	    imgGraphics.CopyFromScreen(p1.X, p1.Y, 0, 0, new System.Drawing.Size((int)w, (int)h));
	    BitmapSource source = loadBitmap(image);
	    return source;
	
// RenderTargetBitmap bitmap = new RenderTargetBitmap(w, h, 96, 96, PixelFormats.Default); // bitmap.Render(visual); // return bitmap; }

Now, The application gives me a invalidOperation exception with the "This Visual is not connected to a PresentationSource" message as soon as it starts. Note that each of my tabitems has the web browser control.

  Any way to overcome this?

Futurix

Coordinator
Aug 24, 2011 at 12:14 PM

Futurix,

It looks like you should be able to check IsVisible before calling PointToScreen() per http://stackoverflow.com/questions/391732/how-do-you-know-if-your-wpf-control-is-being-rendered

Good luck.

If you get it to work, please add a post with a description of what you had to do.

Thanks,

Josh

Aug 25, 2011 at 9:02 AM

Finally got it to work as wanted. The following are the methods that I had to modify

//in fabtabcontrol.cs

public int PreviousSelectedIndex { get; set; }

protected override void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            if (!_itemsChanging)
            {
                DidSelectionChange = true;
            }
            //have to check _itemsChanging for performance reasons, otherwise this method
            //gets called when we force renders for adding/removing tabs, and then we're constantly'
            //updating the snapshots WAY more than we need to.
            if (this.ShowContentsTab && !_itemsChanging)
            {
         	   UpdateContentsTabViewsIfNecessary();
                _itemsStrategy.JuggleHiddenContent(e, args => base.OnSelectionChanged(args));
                
                //this only needs to happen if we are in this method because the user actually
                //change the tab they selected, and not when new items are added or removed
                //to the collection and ForceRenderItems  (which forces selection of all items)
                //is called from OnItemsChanged---thus the _itemsChanging check above
               // UpdateContentsTabViewsIfNecessary();
            }
            
            base.OnSelectionChanged(e);

            DidSelectionChange = false;
        }

void FabTabControl_Loaded(object sender, RoutedEventArgs e)
        {
            AddContentsTabIfNecessary();
            if (this.ShowContentsTab)
            {
                ForceItemRender();
                UpdateContentsTabViewsIfNecessary();
            }
		this.PreviousSelectedIndex = this.SelectedIndex;
        }

 private void UpdateContentsTabViewsIfNecessary()
        {
            if (ShowContentsTab && _contentsTabAdded && this.Items.Count > 1)
            {
                ContentTabView view = this.Items[0] as ContentTabView;
                if (view != null)
                {
			view.SetViews(BuildDictionaryOfViewsAndHeaders(),this.PreviousSelectedIndex);
			PreviousSelectedIndex = this.SelectedIndex;  
                }
            }
        }

//in contenttabview.xaml.cs

 internal void SetViews(Dictionary<object, object> views,int snapshotTabIndex)
        {
            _views = views;
            UpdateViews(snapshotTabIndex);

        }

private void UpdateViews(int snapshotTabIndex)
        {
            if (_views != null)
            {
                this.wrapPanel.Children.Clear();
                UpdateViewSnapshots(snapshotTabIndex);
            }
        }

 private void UpdateViewSnapshots(int snapshotTabIndex)
        {
	  FrameworkElement element;
		if (snapshotTabIndex > 0) {
			element = _views.Keys.ToList()[snapshotTabIndex-1] as FrameworkElement;
			if (ShouldTakeSnapShot(element)) {
			BitmapSource bitmapSource = _bitmapBuilder.GetBitmapSourceFromElement(GetElementForSnapshot(element));
			_toolTipBuilder.SetImageScreenshotOnFabTabItemAttachedProperty(GetElementForSnapshot(element), bitmapSource);
			}
		}
	foreach (object view in _views.Keys)
            {
                element = view as FrameworkElement;
                element = CheckForHiddenElement(view, element);
                if (ShouldTakeSnapShot(element))
               {
		   Image imageForButton= _toolTipBuilder.GetImageScreenshotOnFabTabItemAttachedProperty(GetElementForSnapshot(element));
                   wrapPanel.Children.Add(_imageButtonFactory.CreateImageButton(view, imageForButton));
									
                }
            }
        }

//in bitmapsourcebuilder.cs

 internal BitmapSource CreateBitmap(FrameworkElement element)
        {
            if (element == null)
                return null;

            ForceRenderIfElementIsInsideAHiddenListView(element);

            DrawingVisual visual;
            int w;
            int h;

            GetInformationForRenderTargetBitmap(element, out visual, out w, out h);

            if (w == 0 || h == 0)
                return null;

		Rect bounds = VisualTreeHelper.GetDescendantBounds(element);
		if (System.Windows.PresentationSource.FromVisual(element) != null) {
		System.Windows.Point p0 = element.PointToScreen(bounds.TopLeft);
		System.Drawing.Point p1 = new System.Drawing.Point((int)p0.X, (int)p0.Y);
		System.Drawing.Bitmap image = new System.Drawing.Bitmap((int)bounds.Width, (int)bounds.Height);
		System.Drawing.Graphics imgGraphics = System.Drawing.Graphics.FromImage(image);
		imgGraphics.CopyFromScreen(p1.X, p1.Y, 0, 0, new System.Drawing.Size((int)bounds.Width, (int)bounds.Height));
		BitmapSource source = loadBitmap(image);
		 return source;
		} else {
			
		  RenderTargetBitmap bitmap = new RenderTargetBitmap(w, h, 96, 96, PixelFormats.Default);
		  bitmap.Render(visual);
		  return bitmap;
		}
        }

// tooltipbuilder.cs

//create method
public Image GetImageScreenshotOnFabTabItemAttachedProperty(FrameworkElement element) {
					
	FabTabItem item = element.Parent as FabTabItem;
	if (item == null) {
	item = element as FabTabItem;
	}
	item = GetItemContainer(element, item);
	if (item != null) {
	return FabTabItemProperties.GetFabTabItemImage(item);
	} else {
	throw new InvalidOperationException("Cannot create rich tooltip because FabTabItem cannot be resolved");
	}
}

 private static Image CreateImageForToolTip(BitmapSource bitmap)
        {
            //TODO: Make the size of the tooltip image user-configurable?
            Image tooltipImage = new Image();
            tooltipImage.Source = bitmap;
            tooltipImage.Height = 150;
            tooltipImage.Width = 200;
            //changed to UniformToFill because Uniform caused weird behavior if entire windows
            //were resized
            tooltipImage.Stretch = Stretch.UniformToFill;
            return tooltipImage;
        }

//in imagebuttonfactory.cs

 public ImageButton CreateImageButton(object view, Image image)
        {
            ImageButton imageButton = null;
	    Image newImage = null;  
	     if(image!=null)
             newImage = CreateImageForButton(image.Source);
					
                imageButton = new ImageButton();
		if (newImage != null)
		 imageButton.Content = newImage;
		else
		 imageButton.Content = " ";

                imageButton.Style = _tabControl.ContentTabImageButtonStyle;
                object title = null;
                if (_contentTabView.Views.TryGetValue(view, out title))
                {
                    imageButton.Title = title.ToString();
                }

                imageButton.Click += new RoutedEventHandler(imageButton_Click);
                imageButton.ApplyTemplate();
                SetupCloseButton(view, imageButton);
            
            return imageButton;

        }


- Futurix

Coordinator
Aug 25, 2011 at 12:12 PM

Awesome, thanks for sharing your solution!

Josh