Is it possible to make a Popup act as a Layered Window - c#

I am wonder if a PopUp can be A LayeredWindow.
I am using Encoder 4 and there is a property that allows the program to not capture layered window.
Here is my code to show the feed in a tooltip
public class MyToolTip : ToolTip
{
protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate)
{
if (newTemplate != null)
{
this.Visibility = Visibility.Collapsed;
this.IsOpen = true;
Popup popup = GetPopupFromVisualChild(this);
if (popup != null)
{
popup.AllowsTransparency = false;
}
this.IsOpen = false;
this.Visibility = Visibility.Visible;
}
}
private static Popup GetPopupFromVisualChild(Visual child)
{
Visual parent = child;
FrameworkElement visualRoot = null;
while (parent != null)
{
visualRoot = parent as FrameworkElement;
parent = VisualTreeHelper.GetParent(parent) as Visual;
}
Popup popup = null;
if (visualRoot != null)
{
popup = visualRoot.Parent as Popup;
}
//popup.
return popup;
}
}
Wpf :
<Grid>
<Button Width="10" Height="10" Click="Button_Click">
<Button.ToolTip>
<w:MyToolTip Height="500" Width="550" StaysOpen="True">
<WindowsFormsHost x:Name="wrapper" Margin="0,0,0,0" Background="{x:Null}">
<wf:Panel x:Name="previewScreen" BackColor="Transparent" Size="500,500" >
<wf:Panel.Controls>
<wf:Panel x:Name="PreviewScreen2" BackColor="Transparent" Size="500,500"></wf:Panel>
</wf:Panel.Controls>
</wf:Panel>
</WindowsFormsHost>
</w:MyToolTip>
</Button.ToolTip>
</Button>
</Grid>
This issue is Encoder 4, only accept a HandleRef for the preview window.
This is what i DO with Encoder :
MediaSource is a LiveDeviceSource
if (mediaSource != null && mediaSource.PreviewWindow == null)
mediaSource.PreviewWindow =
new PreviewWindow(new HandleRef(PreviewWindow.PreviewScreen2, PreviewWindow.PreviewScreen2.Handle));
What i want is to have a tooltip that shows the webcam preview but not being recorded with the screen.
If I Don't use the Popup, the feed doesn't show. Altought Encoder understand it's a LayeredWindow and doesn't record it.
If I use the popup the feed shows but it's being recorded.
Somehow it's not a layeredWindow anymore even if it's in a tooltip.
Some help would be greatly apprecied, and rewarded =)

Related

Null values when I try to reach Rectangle

I have a uwp project that i have a booking function in and would be pleased to have some help with one thing.
So i'm trying to reach a Rectangle in my UserControl from my Main.xaml.cs file, so i can set the Rectangles fill property.
This is how i have done it:
Method in Main.xaml.cs for finding the child property:
private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
{
int childNumber = VisualTreeHelper.GetChildrenCount(control);
for (int i = 0; i < childNumber; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(control, i);
FrameworkElement fe = child as FrameworkElement;
// Not a framework element or is null
if (fe == null) return null;
if (child is T && fe.Name == ctrlName)
{
// Found the control so return
return child;
}
else
{
// Not found it - search children
DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
return nextLevel;
}
}
return null;
}
Inside the function where i want to call the Rectangle that is named StatusColor I do this:
Rectangle Rec = FindChildControl<Rectangle>(GridView1, "StatusColor") as Rectangle;
But somehow when I try to execute the code I get this error for the variable Rec:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
I know there are many posts about this exception but i still not getting any smarter by looking at them...
But as i said, I would be very pleased with someones help
Thanks in advance!
EDIT:
My xaml in Main.xaml to declare the UserControl:
<GridView x:Name="GridView1" ItemContainerStyle="{StaticResource testgrid}" ItemsSource="{x:Bind Rooms}" Width="1740" Height="835" IsHitTestVisible="False" ScrollViewer.HorizontalScrollBarVisibility="Hidden" Margin="75,190,75,100" FontFamily="Segoe MDL2 Assets" IsDoubleTapEnabled="False" IsHoldingEnabled="False" IsRightTapEnabled="False" IsTapEnabled="False">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:Room">
<local:TemplateGrid x:Name="TemplateGrid"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
And this is how my code looks like for the Rectangle:
<Rectangle x:Name="StatusColor" x:FieldModifier="public" Margin="0,0,0,0" Height="218" VerticalAlignment="Top">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#00000000" Offset="0.901"/>
<GradientStop Color="#CC17FF00" Offset="0"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
It is these lines:
// Not a framework element or is null
if (fe == null) return null;
You are exiting the loop too early. When the element i is not a framework element, you should just ignore it and continue on to the next one.
So instead of exiting when you encounter a non-framework element, just execute the next lines only when it is one:
if (fe != null)
{
// rest of checking
}
or alternatively:
if (fe == null) continue;
EDIT
A slight reworking of your code to:
private T FindChildControl<T>(DependencyObject control, string ctrlName)
where T: FrameworkElement
{
int childNumber = VisualTreeHelper.GetChildrenCount(control);
for (int i = 0; i < childNumber; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(control, i);
FrameworkElement fe = child as FrameworkElement;
// Not a framework element or is null
if (fe == null)
{
continue;
}
if (child is T && fe.Name == ctrlName)
{
// Found the control so return
return (T)child;
}
else
{
// Not found it - search children
T nextLevel = this.FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
{
return nextLevel;
}
}
}
return null;
}
should be called with
Rectangle rec = FindChildControl<Rectangle>(GridView1, "StatusColor");
to give the correct result. At least it did in my test situation (with adjusted parameters).
The only real change was the use of continue instead of return. Furthermore I made use of generics to immediately return the correct type, no casting needed.

Prevent WPF controls from overlapping on MouseMove event

I'm working on a dynamic C# WPF application (on Windows 10) that uses a fullscreen Grid. Controls are added to the grid dynamically at runtime (which are managed in a Dictionary<>) and I recently added code to move the controls along the grid with the mouse (also at runtime) using a TranslateTransform (which I am now doubting the viability of).
Is there a way I can prevent the controls from overlapping or "sharing space" on the grid when moving them? In other words, adding some sort of collision detection. Would I use an if statement to check the control margin ranges or something? My move events are shown below:
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
// Orientation variables:
public bool _isInDrag = false;
public Dictionary<object, TranslateTransform> PointDict = new Dictionary<object, TranslateTransform();
public Point _anchorPoint;
public Point _currentPoint;
public MainWindow()
{
InitializeComponent();
}
public static void Control_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_isInDrag)
{
var element = sender as FrameworkElement;
element.ReleaseMouseCapture();
_isInDrag = false;
e.Handled = true;
}
}
public static void Control_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var element = sender as FrameworkElement;
_anchorPoint = e.GetPosition(null);
element.CaptureMouse();
_isInDrag = true;
e.Handled = true;
}
public static void Control_MouseMove(object sender, MouseEventArgs e)
{
if (_isInDrag)
{
_currentPoint = e.GetPosition(null);
TranslateTransform tt = new TranslateTransform();
bool isMoved = false;
if (PointDict.ContainsKey(sender))
{
tt = PointDict[sender];
isMoved = true;
}
tt.X += _currentPoint.X - _anchorPoint.X;
tt.Y += (_currentPoint.Y - _anchorPoint.Y);
(sender as UIElement).RenderTransform = tt;
_anchorPoint = _currentPoint;
if (isMoved)
{
PointDict.Remove(sender);
}
PointDict.Add(sender, tt);
}
}
}
MainWindow.xaml (example):
<Window x:Name="MW" x:Class="MyProgram.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyProgram"
mc:Ignorable="d"
Title="MyProgram" d:DesignHeight="1080" d:DesignWidth="1920" ResizeMode="NoResize" WindowState="Maximized" WindowStyle="None">
<Grid x:Name="MyGrid" />
<Image x:Name="Image1" Source="pic.png" Margin="880,862,0,0" Height="164" Width="162" HorizontalAlignment="Left" VerticalAlignment="Top" MouseLeftButtonDown="Control_MouseLeftButtonDown" MouseLeftButtonUp="Control_MouseLeftButtonUp" MouseMove="Control_MouseMove" />
<TextBox x:Name="Textbox1" Margin="440,560,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" MouseLeftButtonDown="Control_MouseLeftButtonDown" MouseLeftButtonUp="Control_MouseLeftButtonUp" MouseMove="Control_MouseMove" />
</Window>
Edit: It seems that moving a control with a TranslateTransform does not change the margin for that control. Not sure why.
Edit 2: Not getting much traction. If anyone needs clarification on anything, please ask.
Edit 3: Pretty sure I can't use TranslateTransform because it does not change the margin of a given control. Is there an alternative?
Edit 4: Added some 'boilerplate' code for those who want to copy & paste. Let me know if you have any questions about it.
TL;DR: Demo from the bottom of this answer
When you want to modify your UI without adding event handlers to every single control, the way to go is with Adorners. Adorners are (as the name implies) controls that adorn another control to add additional visuals or as in your case functionality. Adorners reside in an AdornerLayer which you can either add yourself or use the one that every WPF Window already has. The AdornerLayer is on top of all your other controls.
You never mentioned what should happen when the user lets go of the mouse button when controls overlap so I just reset the control to its original position if that happens.
At this point I'd usually explain what to keep in mind when moving controls but since your original example even contains the CaptureMouse people usually forget, I think you'll understand the code without further explanation :)
A couple of things you might want to add / improve:
A snap to grid feature (pixel precise movement can be a bit overwhelming for the average user)
Take RenderTransform, LayoutTransform and non-rectangular shapes (if needed) into account when calculating the overlap
Move the editing functionality (enable, disable, etc.) into a separate control and add a dedicated AdornerLayer
Disable interactive controls (Buttons, TextBoxes, ComboBoxes, etc.) in edit-mode
Cancel movement when the user presses Esc
Restrict movement to the bounds of the parent container done
Move the active Adorner to the top of the AdornerLayer
Let the user move multiple controls at once (typically by selecting them with Ctrl)
Previously unanswered question:
Are you saying controls are no longer assigned a margin when using TranslateTransform?
Not at all - You could use a combination of Grid.Row, Grid.Column, Margin, RenderTransform and LayoutTransform but then it would be a nightmare to determine where the control is actually displayed. If you stick with one (In this case for example Margin or LayoutTransform) it is much easier to work with and keep track of. If you ever find yourself in a situation where you need more than one at the same time, you would have to find the actual position by determining the corners of the control by transforming (0, 0) and (ActualWidth, ActualHeight) with TransformToAncestor. Trust me, you don't want to go there - keep it simple, stick with one of them.
The below code is not the "holy grail of how to move things" but it should give you an idea of how to do it and what else you could do with it (resize, rotate, remove controls, etc.). The layouting is based purely on the Left and Top margin of the controls. It shouldn't be to hard to swap out all Margins for LayoutTransforms if you prefer that, as long as you keep it consistent.
Move Adorner
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
public class MoveAdorner : Adorner
{
// The parent of the adorned Control, in your case a Grid
private readonly Panel _parent;
// Same as "AdornedControl" but as a FrameworkElement
private readonly FrameworkElement _child;
// The visual overlay rectangle we can click and drag
private readonly Rectangle _rect;
// Our own collection of child elements, in this example only _rect
private readonly UIElementCollection _visualChildren;
private bool _down;
private Point _downPos;
private Thickness _downMargin;
private List<Rect> _otherRects;
protected override int VisualChildrenCount => _visualChildren.Count;
protected override Visual GetVisualChild(int index)
{
return _visualChildren[index];
}
public MoveAdorner(FrameworkElement adornedElement) : base(adornedElement)
{
_child = adornedElement;
_parent = adornedElement.Parent as Panel;
_visualChildren = new UIElementCollection(this,this);
_rect = new Rectangle
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
StrokeThickness = 1,
};
SetColor(Colors.LightGray);
_rect.MouseLeftButtonDown += RectOnMouseLeftButtonDown;
_rect.MouseLeftButtonUp += RectOnMouseLeftButtonUp;
_rect.MouseMove += RectOnMouseMove;
_visualChildren.Add(_rect);
}
private void SetColor(Color color)
{
_rect.Fill = new SolidColorBrush(color) {Opacity = 0.3};
_rect.Stroke = new SolidColorBrush(color) {Opacity = 0.5};
}
private void RectOnMouseMove(object sender, MouseEventArgs args)
{
if (!_down) return;
Point pos = args.GetPosition(_parent);
UpdateMargin(pos);
}
private void UpdateMargin(Point pos)
{
double deltaX = pos.X - _downPos.X;
double deltaY = pos.Y - _downPos.Y;
Thickness newThickness = new Thickness(_downMargin.Left + deltaX, _downMargin.Top + deltaY, 0, 0);
//Restrict to parent's bounds
double leftMax = _parent.ActualWidth - _child.ActualWidth;
double topMax = _parent.ActualHeight - _child.ActualHeight;
newThickness.Left = Math.Max(0, Math.Min(newThickness.Left, leftMax));
newThickness.Top = Math.Max(0, Math.Min(newThickness.Top, topMax));
_child.Margin = newThickness;
bool overlaps = CheckForOverlap();
SetColor(overlaps ? Colors.Red : Colors.Green);
}
// Check the current position for overlaps with all other controls
private bool CheckForOverlap()
{
if (_otherRects == null || _otherRects.Count == 0)
return false;
Rect thisRect = GetRect(_child);
foreach(Rect otherRect in _otherRects)
if (thisRect.IntersectsWith(otherRect))
return true;
return false;
}
private Rect GetRect(FrameworkElement element)
{
return new Rect(new Point(element.Margin.Left, element.Margin.Top), new Size(element.ActualWidth, element.ActualHeight));
}
private void RectOnMouseLeftButtonUp(object sender, MouseButtonEventArgs args)
{
if (!_down) return;
Point pos = args.GetPosition(_parent);
UpdateMargin(pos);
if (CheckForOverlap())
ResetMargin();
_down = false;
_rect.ReleaseMouseCapture();
SetColor(Colors.LightGray);
}
private void ResetMargin()
{
_child.Margin = _downMargin;
}
private void RectOnMouseLeftButtonDown(object sender, MouseButtonEventArgs args)
{
_down = true;
_rect.CaptureMouse();
_downPos = args.GetPosition(_parent);
_downMargin = _child.Margin;
// The current position of all other elements doesn't have to be updated
// while we move this one so we only determine it once
_otherRects = new List<Rect>();
foreach (FrameworkElement child in _parent.Children)
{
if (ReferenceEquals(child, _child))
continue;
_otherRects.Add(GetRect(child));
}
}
// Whenever the adorned control is resized or moved
// Update the size of the overlay rectangle
// (Not 100% necessary as long as you only move it)
protected override Size MeasureOverride(Size constraint)
{
_rect.Measure(constraint);
return base.MeasureOverride(constraint);
}
protected override Size ArrangeOverride(Size finalSize)
{
_rect.Arrange(new Rect(new Point(0,0), finalSize));
return base.ArrangeOverride(finalSize);
}
}
Usage
private void DisableEditing(Grid theGrid)
{
// Remove all Adorners of all Controls
foreach (FrameworkElement child in theGrid.Children)
{
var layer = AdornerLayer.GetAdornerLayer(child);
var adorners = layer.GetAdorners(child);
if (adorners == null)
continue;
foreach(var adorner in adorners)
layer.Remove(adorner);
}
}
private void EnableEditing(Grid theGrid)
{
foreach (FrameworkElement child in theGrid.Children)
{
// Add a MoveAdorner for every single child
Adorner adorner = new MoveAdorner(child);
// Add the Adorner to the closest (hierarchically speaking) AdornerLayer
AdornerLayer.GetAdornerLayer(child).Add(adorner);
}
}
Demo XAML
<Grid>
<Button Content="Enable Editing" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="100" Click="BtnEnable_Click"/>
<Button Content="Disable Editing" HorizontalAlignment="Left" Margin="115,10,0,0" VerticalAlignment="Top" Width="100" Click="BtnDisable_Click"/>
<Grid Name="grid" Background="AliceBlue" Margin="10,37,10,10">
<Button Content="Button" HorizontalAlignment="Left" Margin="83,44,0,0" VerticalAlignment="Top" Width="75"/>
<Ellipse Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="207,100,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="33,134,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>
</Grid>
</Grid>
Expected Result
When editing is disabled controls cannot be moved, interactive controls can be clicked / interacted with without obstruction. When editing mode is enabled, each control is overlayed with an adorner that can be moved. If the target position overlaps with another control, the adorner will turn red and the margin will be reset to the initial position if the user lets go of the mouse button.
There is no other way then to check if there control exists on place where you are moving.
Since you are moving UI elements a lot it is better to use canvas instead of grid where you can layout elements with Top and Left parameters.
Here is modified code of yours that do that
public partial class MainWindow : Window
{
public bool _isInDrag = false;
public Dictionary<object, TranslateTransform> PointDict = new Dictionary<object, TranslateTransform>();
public Point _anchorPoint;
public Point _currentPoint;
public MainWindow()
{
InitializeComponent();
}
public void Control_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_isInDrag)
{
var element = sender as FrameworkElement;
element.ReleaseMouseCapture();
Panel.SetZIndex(element, 0);
_isInDrag = false;
e.Handled = true;
}
}
public void Control_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var element = sender as FrameworkElement;
_anchorPoint = e.GetPosition(null);
element.CaptureMouse();
Panel.SetZIndex(element, 10);
_isInDrag = true;
e.Handled = true;
}
public void Control_MouseMove(object sender, MouseEventArgs e)
{
if (_isInDrag)
{
_currentPoint = e.GetPosition(null);
FrameworkElement fw = sender as FrameworkElement;
if (fw != null)
{
FrameworkElement fwParent = fw.Parent as FrameworkElement;
if (fwParent != null)
{
Point p = new Point(_currentPoint.X - _anchorPoint.X + Canvas.GetLeft((sender as UIElement)), _currentPoint.Y - _anchorPoint.Y + Canvas.GetTop((sender as UIElement)));
List<HitTestResult> lst = new List<HitTestResult>()
{
VisualTreeHelper.HitTest(fwParent , p),
VisualTreeHelper.HitTest(fwParent, new Point(p.X + fw.Width, p.Y)),
VisualTreeHelper.HitTest(fwParent, new Point(p.X, p.Y + fw.Height)),
VisualTreeHelper.HitTest(fwParent, new Point(p.X + fw.Width, p.Y +fw.Height)),
};
bool success = true;
foreach (var item in lst)
{
if (item != null)
{
if (item.VisualHit != sender && item.VisualHit != fwParent && fw.IsAncestorOf(item.VisualHit) == false)
{
success = false;
break;
}
}
}
if (success)
{
Canvas.SetTop((sender as UIElement), p.Y);
Canvas.SetLeft((sender as UIElement), p.X);
_anchorPoint = _currentPoint;
}
}
}
}
}
}
Xaml
<Window x:Class="ControlsOverlapWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ControlsOverlapWpf"
mc:Ignorable="d"
Title="MyProgram" d:DesignHeight="500" d:DesignWidth="500" ResizeMode="NoResize" WindowState="Normal" WindowStyle="None">
<Canvas Background="Pink">
<Button Canvas.Top=" 200" Canvas.Left="200" Height="150" Width="150" Background="Aqua" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewMouseLeftButtonDown="Control_MouseLeftButtonDown" PreviewMouseLeftButtonUp="Control_MouseLeftButtonUp" PreviewMouseMove="Control_MouseMove" />
<Button Canvas.Top=" 200" Canvas.Left="200" Height="150" Width="150" Background="Aqua" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewMouseLeftButtonDown="Control_MouseLeftButtonDown" PreviewMouseLeftButtonUp="Control_MouseLeftButtonUp" PreviewMouseMove="Control_MouseMove" />
<Button Canvas.Top=" 200" Canvas.Left="200" Height="150" Width="150" Background="Aqua" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewMouseLeftButtonDown="Control_MouseLeftButtonDown" PreviewMouseLeftButtonUp="Control_MouseLeftButtonUp" PreviewMouseMove="Control_MouseMove" />
<Button Canvas.Top=" 200" Canvas.Left="200" Height="150" Width="150" Background="Aqua" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewMouseLeftButtonDown="Control_MouseLeftButtonDown" PreviewMouseLeftButtonUp="Control_MouseLeftButtonUp" PreviewMouseMove="Control_MouseMove" />
<Button Canvas.Top=" 200" Canvas.Left="200" Height="150" Width="150" Background="Aqua" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewMouseLeftButtonDown="Control_MouseLeftButtonDown" PreviewMouseLeftButtonUp="Control_MouseLeftButtonUp" PreviewMouseMove="Control_MouseMove" />
<Button Canvas.Top=" 200" Canvas.Left="200" Height="150" Width="150" Background="Aqua" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewMouseLeftButtonDown="Control_MouseLeftButtonDown" PreviewMouseLeftButtonUp="Control_MouseLeftButtonUp" PreviewMouseMove="Control_MouseMove" />
</Canvas>
</Window>

How to show tooltip in code behind in WPF

How can I show a tooltip in code-behind? The code below defines my question better. Obviously I don't want the code to check for mouse position etc, just how to display the tooltip.
private void UIElement_OnMouseMove(object sender, MouseEventArgs e)
{
// if mouse position equals certain coordinates show the tooltip
}
Try like this:
if (control.ToolTip != null)
{
// Main condition
if (control.ToolTip is ToolTip)
{
var castToolTip = (ToolTip)control.ToolTip;
castToolTip.IsOpen = true;
}
else
{
toolTip.Content = control.ToolTip;
toolTip.StaysOpen = false;
toolTip.IsOpen = true;
}
}
The Main condition necessary, because ToolTip for Control can be set in two approaches:
First approach
<Button Name="TestButton"
ToolTip="TestToolTip" />
This approach is most common. In this case, the content of the ToolTip will object and not type of ToolTip.
Second approach
<Button Name="TestButton"
Content="Test">
<Button.ToolTip>
<ToolTip>TestToolTip</ToolTip>
</Button.ToolTip>
</Button>
Is the same as this:
<Button Name="TestButton"
Content="Test">
<Button.ToolTip>
TestToolTip
</Button.ToolTip>
</Button>
In this case, the Content type of ToolTip will be Tooltip. Note that in the second case, the object automatically fills ToolTip object on line TestToolTip, hence this approach will work a bit slower.
Therefore, this check is needed to avoid an exception when we try to assign to the ToolTip the content of the ToolTip type here:
toolTip.Content = control.ToolTip;
Below is a full example:
XAML
<Grid>
<Button Name="TestButton"
Width="100"
Height="25"
Content="Test"
ToolTip="TestToolTip" />
<Button Name="ShowToolTip"
VerticalAlignment="Top"
Content="ShowToolTip"
Click="ShowToolTip_Click" />
</Grid>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ShowToolTip_Click(object sender, RoutedEventArgs e)
{
var toolTip = new ToolTip();
if (TestButton.ToolTip != null)
{
if (TestButton.ToolTip is ToolTip)
{
var castToolTip = (ToolTip)TestButton.ToolTip;
castToolTip.IsOpen = true;
}
else
{
toolTip.Content = TestButton.ToolTip;
toolTip.StaysOpen = false;
toolTip.IsOpen = true;
}
}
}
}

MenuContext not show when holding in WebBrowser Component Windows Phone 8

When holding in Internet Explorer app, it show a menu context for extra actions(open in new tab, copy link, share link) like this pictures
![Internet Explorer][1]
[1]: http://i.stack.imgur.com/2xNv9.png
But when i add a WebBrowser Component in my Windows Phone 8 project, holding a link but it not show anything. This is xaml code of WebBrowser Component
<phone:WebBrowser Name="webBrowser" IsScriptEnabled="True" Margin="0" Background="Transparent" />
Any one can tell my why and how to fix this?
I tried this but not work
XAML
<phone:WebBrowser Name="webBrowser" IsScriptEnabled="True" Margin="0" Background="Transparent">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu x:Name="menu1">
<toolkit:MenuItem Header="item1" Click="MenuItem_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</phone:WebBrowser>
C#
public void AttachContextMenu()
{
try
{
if (webBrowser.IsScriptEnabled)
{
webBrowser.InvokeScript("execScript", "function FindParentLink(item) \r\n{\r\n\tif (!item.parentNode)\r\n\t\treturn null;\r\n\tif (item.tagName.toLowerCase() == 'a') \r\n\t{\r\n\t\treturn item;\r\n\t} \r\n\telse \r\n\t{\r\n\t\treturn FindParentLink(item.parentNode);\r\n\t}\r\n}\r\n\r\nfunction FindParentImage(item) \r\n{\r\n\tif (!item.parentNode)\r\n\t\treturn null;\r\n\tif (item.tagName.toLowerCase() == 'img') \r\n\t{\r\n\t\treturn item;\r\n\t} \r\n\telse \r\n\t{\r\n\t\treturn FindParentImage(item.parentNode);\r\n\t}\r\n}\r\n\r\nfunction HandleContextMenu() \r\n{\r\n\tvar linkItem = FindParentLink(event.srcElement);\r\n var imageItem = FindParentImage(event.srcElement);\r\n var notifyOutput = '';\r\n if (linkItem != null) if (linkItem.href != null) notifyOutput += linkItem.href;\r\n if (imageItem != null) if (imageItem.src != null) notifyOutput += imageItem.src;\r\n if (notifyOutput != '')\r\n window.external.notify(notifyOutput);\r\n else\r\n\t\twindow.external.notify('NOTLINKIMG');\r\n}");
webBrowser.InvokeScript("execScript", "document.oncontextmenu = HandleContextMenu;");
}
}
catch
{
}
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
AttachContextMenu();
}

Use WindowsFormHost inside a wpf tooltip

i am trying to host a windows form panel inside a ToolTip.
Below is the Xaml code and the class behind for the ToolTip.
The issue is if I'm using windowsFormsHost the panel doesnt change the color, it feels like the ToolTip doesn't even know it's there.
Am I doing it right?
(If I'm able to change the color then I will use it to show a liveFeed of a camera)
When I click on the button, the ToolTip is there but it stays basic.
If I have no Windows Form Host and use a StackPanel then it works.
But I need to use the Panel.
Xaml :
<Grid>
<Button Width="100" Height="100">
<Button.ToolTip>
<Controls:MyToolTip Height="500" Width="550">
<WindowsFormsHost x:Name="wrapper" Margin="0,0,0,0" Background="{x:Null}">
<wf:Panel x:Name="previewScreen" BackColor="Purple" Size="200,200" >
</wf:Panel>
</WindowsFormsHost>
</Controls:MyToolTip>
</Button.ToolTip>
</Button>
</Grid>
C# :
public class MyToolTip : ToolTip
{
protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate)
{
if (newTemplate != null)
{
this.Visibility = Visibility.Collapsed;
this.IsOpen = true;
Popup popup = GetPopupFromVisualChild(this);
if (popup != null) popup.AllowsTransparency = false;
this.IsOpen = false;
this.Visibility = Visibility.Visible;
}
}
private static Popup GetPopupFromVisualChild(Visual child)
{
Visual parent = child;
FrameworkElement visualRoot = null;
while (parent != null)
{
visualRoot = parent as FrameworkElement;
parent = VisualTreeHelper.GetParent(parent) as Visual;
}
Popup popup = null;
if (visualRoot != null)
{
popup = visualRoot.Parent as Popup;
}
return popup;
}
}
Thanks for your time and help.
The problem is that the panel has no content, so It doesn't show the background.
Try this:
<Grid>
<Button Width="100" Height="100">
<Button.ToolTip>
<Controls:MyToolTip >
<WindowsFormsHost x:Name="wrapper" Margin="0,0,0,0" Background="{x:Null}" >
<wf:Panel x:Name="previewScreen" BackColor="Purple" Size="200,200" >
<wf:Panel.Controls>
<wf:Label Text="Test"></wf:Label>
</wf:Panel.Controls>
</wf:Panel>
</WindowsFormsHost>
</Controls:MyToolTip>
</Button.ToolTip>
</Button>
</Grid>

Categories

Resources