need help understanding event bubbling code in WPF - c#

the following code was supposed to turn all the buttons present in the form into green color on one of the button clicks due to event bubbling, but on my machine on Visual studio 2008, it is turning only the clicked button as green, could you please help in figuring out the problem?
XAML Code (window1.xaml):
<Window x:Class="EventRouting.Window1" Title="Event Routing" Height="300" Width="300"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Border Margin="15" BorderBrush="Blue" BorderThickness="5" Padding="15"
CornerRadius="12" x:Name="myBorder" Background="Transparent">
<StackPanel x:Name="myPanel" Background="Transparent">
<Ellipse x:Name="myEllipse" Margin="3" Fill="Green" Height="40" />
<Rectangle x:Name="myRectangle" Margin="3" Fill="Cyan" Height="40" RadiusX="10" RadiusY="10" />
</StackPanel>
CS code (window1.xaml.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
namespace EventRouting
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.MouseEnter += MouseEnterHandler;
myBorder.MouseEnter += MouseEnterHandler;
myPanel.MouseEnter += MouseEnterHandler;
myEllipse.MouseEnter += MouseEnterHandler;
myRectangle.MouseEnter += MouseEnterHandler;
this.MouseDown += MouseDownHandler;
myBorder.MouseDown += MouseDownHandler;
myPanel.MouseDown += MouseDownHandler;
myEllipse.MouseDown += MouseDownHandler;
myRectangle.MouseDown += MouseDownHandler;
for (int i = 1; i <= 5; ++i)
{
Button btn = new Button();
btn.Content = "Button " + i;
myPanel.Children.Add(btn);
//btn.Click += new RoutedEventHandler(btn_Click);
}
myPanel.AddHandler(Button.ClickEvent, new RoutedEventHandler(btn_Click));
}
void btn_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button) e.Source;
btn.Background = Brushes.Green;
}
void MouseEnterHandler(object sender, MouseEventArgs e)
{
Debug.WriteLine("MouseEnter: " + sender);
}
void MouseDownHandler(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("MouseDown: " + sender);
e.Handled = true;
}
}
}

Routed events bubble up the visual tree until they get handled. Using your XAML, try this code out.
public MainWindow()
{
InitializeComponent();
myEllipse.AddHandler(UIElement.MouseDownEvent, new RoutedEventHandler(OnMouseDown));
myPanel.AddHandler(UIElement.MouseDownEvent, new RoutedEventHandler(OnMouseDown));
myBorder.AddHandler(UIElement.MouseDownEvent, new RoutedEventHandler(OnMouseDown));
}
void OnMouseDown(object sender, RoutedEventArgs e)
{
UIElement uiElement = sender as UIElement;
Debug.WriteLine(uiElement.GetType().ToString());
e.Handled = true;
}
if you comment out the e.Handled = true line, the event will bubble up to parent elements. Here is a good link for you.

If I understand what you want is a tunnel event from the root (the panel) to each child (the buttons). Routed tunnel events don't do that, they only traverse from the root to the the source element, not to siblings. See Overview of routed events in WPF with a great illustration of this.

Because the event handler btn_Click(object sender, MouseEventArgs e) is sending the button you clicked only you can't use the sender object alone to change the text to green.
You should be doing something like foreach (Button btn in myPanel.Children) where you loop through all of your buttons and change the color in your loop.

Related

C# WPF window - internet explorer

I need help from someone who work in C#. I'm trying to achieve WPF application that open internet explorer on URL that i supplement him as a parameter. So in perfect world i would like run something like this:
\\path\window.exe X x Y "URL" "Title"
Where X,Y is windows height and width, URL and Title is a title of that window. My knowledge of C# is nonexistent so after extensive use of google i manage to get this XAML:
<Window x:Class="WPFWebControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="My Web Browser" WindowState="Normal" Loaded="Window_Loaded" WindowStyle="ThreeDBorderWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="Auto" Width="Auto">
<Grid>
<WebBrowser Height="Auto" HorizontalAlignment="Left" Margin="0,28,0,0" Name="MyWebBrowser" VerticalAlignment="Top" Width="Auto" LoadCompleted="MyWebBrowser_LoadCompleted" />
<TextBox Height="23" Margin="40,5,0,0" Name="MyTextBox" VerticalAlignment="Top" HorizontalAlignment="Left" Width="708" />
<Button Content="Go" Margin="10,5,0,476" Name="MyGo" ToolTip="Go" Click="MyGo_Click" RenderTransformOrigin="-0.76,0.565" HorizontalAlignment="Left" Width="25" />
</Grid>
</Window>
and this C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPFWebControl
{ /// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
MyWebBrowser.Source = new Uri("http://www.google.com");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void MyGo_Click(object sender, RoutedEventArgs e)
{
try
{
MyWebBrowser.Source = new Uri("http://" + MyTextBox.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void MyWebBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{}
}
}
Now i need some advice how can i set window size, url and title via parameters so i can get rid of that address textbox and button.
You could open a new window and set a WebBrowser as its Content, e.g.:
WebBrowser browser = new WebBrowser();
Window win = new Window();
win.Content = browser;
win.Height = 100;
win.Width = 100;
win.Show();
win.Title = "title...";
browser.Navigate("http://google.com");
If you want your application to be able to accept command line arguments, you could remove the StartupUri attribute from your App.xaml and override the OnStartup method of your App.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
try
{
double width = Convert.ToDouble(e.Args[0]);
double height = Convert.ToDouble(e.Args[1]);
string title = e.Args[2];
string url = e.Args[3];
WebBrowser browser = new WebBrowser();
Window win = new Window();
win.Content = browser;
win.Height = height;
win.Width = width;
win.Show();
win.Title = title;
browser.Navigate(new Uri(url, UriKind.Absolute));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Usage:
WpfApplication1.exe 100 100 "title..." "http://google.com"
You should be able to use
string[] args = Environment.GetCommandLineArgs();
Or, change teh startup uri in App.xaml (remove it) and instead create your own startup like
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
//Manually create and show your window, passing the arguments
}
}
etc

How to detach from the Visual Tree in WPF

I'm trying to correctly remove a UIElement from an InlineUIContainer in order to use it in another Panel but the program keeps crashing with this message "Specified Visual is already a child of another Visual or the root of a CompositionTarget.".
I've created a small application to illustrate my pain. In this program, once Randy the button is killed\deleted by his girlfriend, he doesn't still detach from his parent, whom I got find out was UIElementIsland. And then any attempt to add Randy as the child of anything else crashes the application (The Apocalypse Button proves my point :) ). You can click to check Randy's parents before\after deleting Randy to notice that he is constantly under UIElementIsland as a child, If he is detached the whole problem\apocalypse should be averted.
It's a Funny application so copy and compile even if it's just for the fun! Any help\ideas would be appreciated!
THE C# Part:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace DetachingfromUIElementIsland
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
int t = 0;
static string[] info = new string[] { "Okay, Lets have a look...", "Checking."
, "Checking..", "Checking...", "Seen it!" };
/// <summary>
/// Makes the App fancy :)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void timer_Tick(object sender, EventArgs e)
{
display.Text = info[t];
if (t == 0)
timer.Interval = new TimeSpan(0, 0, 0, 0, 300);
t++;
if (t >= 4)
{
t = 0;
timer.Stop();
display.Text = GetRandysParent();
}
}
private void deleteRandy_Click(object sender, RoutedEventArgs e)
{
// This might be the bug.
// Maybe there's a better way to do this.
// If there was a VisualTreeHelper.Remove().
randy_container.Child = null;
display.Text = "Haha! I just killed Randy!!! He'll never get the chance"
+ "\n to hurt another woman again!";
display.Background = Brushes.Violet;
end.Visibility = System.Windows.Visibility.Visible;
}
DispatcherTimer timer = null;
/// <summary>
/// Check if Randy is Still attached to UIElementIsland
/// </summary>
/// <returns></returns>
private string GetRandysParent()
{
// Check the visual tree to see if randy is removed properly
DependencyObject dp = VisualTreeHelper.GetParent(randy);
string text = string.Empty;
if (dp != null)
{
display.Background = Brushes.LightGreen;
text = "Randy's Dad is Mr " + dp.ToString();
}
else
{
// This should be what you'll get when the code works properly
display.Background = Brushes.Red;
text = "Weird...Randy doesn't seem to have a dad...";
}
return text;
}
private void findParents_Click(object sender, RoutedEventArgs e)
{
display.Background = Brushes.Yellow;
// Creates a timer to display some fancy stuff
// and then Randy's.
// Just to prove to you that this button actually works.
timer = new DispatcherTimer();
timer.Start();
timer.Tick += timer_Tick;
timer.Interval = new TimeSpan(0, 0, 0, 0, 700);
}
private void randy_Click(object sender, RoutedEventArgs e)
{
// Get Randy to introduce himself
display.Text = "Hi, I'm Randy!!!";
display.Background = Brushes.Orange;
}
private void end_Click(object sender, RoutedEventArgs e)
{
// If randy is removed properly, this would not crash the application.
StackPanel s = new StackPanel();
s.Children.Add(randy);
// CRASH!!!
}
}
}
The XAML:
<Window x:Class="DetachingfromUIElementIsland.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<FlowDocument IsEnabled="True" x:Name="document">
<Paragraph>
<InlineUIContainer x:Name="randy_container">
<!--Meet Randy-->
<Button Name="randy" Content="I am a Randy, the button" Click="randy_Click" ToolTip="Meet Randy"/>
</InlineUIContainer>
<LineBreak/>
<LineBreak/>
<InlineUIContainer x:Name="container2">
<!--Meet Randy's Ex Girlfriend-->
<Button Name="deleteRandy" Content="Randy dumped me for another girl :(, click me to delete him" Click="deleteRandy_Click" ToolTip="Meet Randy's Ex Girlfriend"/>
</InlineUIContainer>
<LineBreak/>
<LineBreak/>
<InlineUIContainer x:Name="container3">
<!--He can help you find Randy's Parents-->
<Button Name="findParents" Content="Click me to find randy's parents" Click="findParents_Click" ToolTip="He can help you find Randy's Parents"/>
</InlineUIContainer>
<LineBreak/>
<LineBreak/>
<InlineUIContainer x:Name="Apocalypse">
<!--End the world, Crash the application-->
<Button x:Name="end" Content="Avenge Randy's Death" Click="end_Click" ToolTip="End the world, Crash the application" Visibility="Hidden"/>
</InlineUIContainer>
</Paragraph>
<Paragraph>
<InlineUIContainer>
<TextBlock x:Name="display" Foreground="Black"/>
</InlineUIContainer>
</Paragraph>
</FlowDocument>
</Window>
The whole code was supposed to be shorter than this, but I spiced it up to make it a bit fun. Hope I brightened someone's day a little. But still, help me :).
Answer:
Derive from Randy's InlineUIContainer as follows:
public class DerivedInlineUIContainer : InlineUIContainer
{
public DerivedInlineUIContainer()
{
}
public void RemoveFromLogicalTree(FrameworkElement f)
{
this.RemoveLogicalChild(f);
}
}
Now you could kill Randy properly this time, and add him to UIElement heaven (The StackPanel):
randy_container.RemoveFromLogicalTree(randy);
IDisposable disp = VisualTreeHelper.GetParent(randy) as IDisposable;
if (disp != null)
disp.Dispose();
// Poor Randy is going to heaven...
StackPanel heaven = new StackPanel();
heaven.add(randy);
Thanks everyone.
Removing the visual parent doesn't seem to help:
private void end_Click(object sender, RoutedEventArgs e)
{
IDisposable disp = VisualTreeHelper.GetParent(randy) as IDisposable;
if (disp != null)
disp.Dispose();
DependencyObject parent = VisualTreeHelper.GetParent(randy);
if (parent == null)
MessageBox.Show("No parent");
// If randy is removed properly, this would not crash the application.
StackPanel s = new StackPanel();
s.Children.Add(randy);
}
So you could either create a new Button:
public MainWindow()
{
InitializeComponent();
randy_container.Child = CreateRandyButton();
}
private void end_Click(object sender, RoutedEventArgs e)
{
StackPanel s = new StackPanel();
s.Children.Add(CreateRandyButton());
}
private Button CreateRandyButton()
{
Button button = new Button { Name = "randy", Content = "I am a Randy, the button", ToolTip = "Meet Randy" };
button.Click += randy_Click;
return button;
}
...or simply hide it as suggested by #Sinatr.
It's funny, but also very noisy. You would get answer much faster if your demo is short.
Instead of removing/adding visual you can simply hide/show it:
void deleteRandy_Click(object sender, RoutedEventArgs e) =>
randy.Visibility = Visibility.Hidden;
void end_Click(object sender, RoutedEventArgs e) =>
randy.Visibility = Visibility.Visible;
This way you are not playing with visual tree in unrecoverable way. You can use MVVM + data templates or x:Shared=False resources if you really want to remove UI element and then add new one.
I found a workaround in case the parent is still a UIElementIsland. Since it implements IDisposable, you can clear its children that way:
var parent = VisualTreeHelper.GetParent(element);
if (parent is IDisposable uiElementIsland)
{
uiElementIsland.Dispose();
}
It's not nice, but it works.

C# ProgressBar not showing progress in media player

everyone. I've encountered a problem while developing my test media player in C#. I think I put all the code, but when I open file, it starts playing but progress bar isn't moving. Here is the code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Media;
using Windows.Storage;
using Windows.Storage.Pickers;
using System.Threading;
using System.Windows;
namespace App1
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += timer_Tick;
timer.Start();
}
TimeSpan _position;
private async void Open_Click(object sender, RoutedEventArgs e)
{
var openPicker = new FileOpenPicker();
openPicker.SuggestedStartLocation = PickerLocationId.VideosLibrary;
openPicker.FileTypeFilter.Add(".wmv");
openPicker.FileTypeFilter.Add(".mp4");
openPicker.FileTypeFilter.Add(".mp3");
var file = await openPicker.PickSingleFileAsync();
if (file != null)
{
var stream = await file.OpenAsync(FileAccessMode.Read);
videoMediaElement.SetSource(stream, file.ContentType);
}
}
private void Play_Click(object sender, RoutedEventArgs e)
{
if(videoMediaElement.PlaybackRate != 1 )
{
videoMediaElement.DefaultPlaybackRate = 1;
}
videoMediaElement.Play();
}
private void Stop_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.Stop();
}
private void ProgressBar_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
}
private void timer_Tick(object sender, object e)
{
if (videoMediaElement.Source != null && videoMediaElement.NaturalDuration.HasTimeSpan)
{
ProgressBar.Minimum = 0;
ProgressBar.Maximum = videoMediaElement.NaturalDuration.TimeSpan.TotalSeconds;
ProgressBar.Value = videoMediaElement.Position.TotalSeconds;
}
}
private void videoMediaElement_MediaOpened(object sender, RoutedEventArgs e)
{
_position = videoMediaElement.NaturalDuration.TimeSpan;
ProgressBar.Minimum = 0;
ProgressBar.Maximum = _position.TotalSeconds;
}
}
}
and XAML:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button x:Name="Open" Content="Open" HorizontalAlignment="Left" Margin="60,564,0,0" VerticalAlignment="Top" Width="299" Click="Open_Click"/>
<Button x:Name="Play" Content="Play" HorizontalAlignment="Left" Margin="393,564,0,0" VerticalAlignment="Top" Width="299" Click="Play_Click"/>
<Button x:Name="Stop" Content="Stop" HorizontalAlignment="Left" Margin="737,564,0,0" VerticalAlignment="Top" Width="299" Click="Stop_Click"/>
<ProgressBar x:Name="ProgressBar"
HorizontalAlignment="Left" Height="16" Margin="60,665,0,0" VerticalAlignment="Top" Width="1185" ValueChanged="ProgressBar_ValueChanged"/>
<Slider x:Name="slider" HorizontalAlignment="Left" Margin="1082,557,0,0" VerticalAlignment="Top" Width="163"/>
<MediaElement x:Name="videoMediaElement" HorizontalAlignment="Left" Height="491.884" Margin="4.22,58.023,0,0" VerticalAlignment="Top" Width="1270.501" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" MediaOpened="videoMediaElement_MediaOpened">
<MediaElement.RenderTransform>
<CompositeTransform Rotation="0.111"/>
</MediaElement.RenderTransform>
</MediaElement>
</Grid>
PLZ HELP!! I wasted 2 days and I found no real solution on google. Thank you!
Well I looked at your code and found your problem. It appears that SetSource() method doesn't really set mediaelement's source. I have no idea why. Maybe someone here will help you with that. There are several things that I can point out.
You start filling this progressbar before the movie starts. Which is a problem. You could initialize your timer not in MainPage constructor but in your Play_Click event or in this case where your movie starts automatically in you Open_Click event.
As I mentioned since the source is always null the progressbar will never fill. Fortunately there is a way to check if video element is currently running. Replace this:
if (videoMediaElement.Source != null && videoMediaElement.NaturalDuration.HasTimeSpan)
With This:
if (videoMediaElement.CurrentState == MediaElementState.Playing)
Hope this helps.

WPF - Webbrowser - getElementById

In a WPF application, I have a webbrowser called WebBrowser1. This refers to an HTML page which contains a TextArea to which users can input text.
<html>
<body>
<textarea class="myStudentInput" id="myStudentInput1">
Text to be copied
</textarea>
</body>
</html>
I wish to get this text and potentially also set this text.
I have tried something similar to the javascript way of writing it:
document.getElementById("myStudentOutput1").innerHTML;
such as
HtmlElement textArea = webBrowser1.Document.All["myStudentInput1"];
dynamic textArea = WebBrowser1.Document.GetElementsByID("myStudentInput1").InnerText;
but it doesn't work.
The following solution in Visual Studio 2015 WPF Application works for me.
First, add a reference to the Microsoft HTML COM Library. This is on the COM tab, when you do an "Add Reference" in your project.
Then add the code:
<Window x:Class="WpfApplication3.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:WpfApplication3"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="800">
<Grid>
<WebBrowser x:Name="WebBrowser1" HorizontalAlignment="Left" Height="480" Margin="10,10,0,0" VerticalAlignment="Top" Width="770" Source="E:\Others\Dropbox\Programming\Questions.html"/>
<Button x:Name="mySetQuestionButton" Content="Set Question" HorizontalAlignment="Left" Margin="200,520,0,0" VerticalAlignment="Top" Width="75" Click="mySetQuestion"/>
<Button x:Name="myGetAnswerButton" Content="Get Answer" HorizontalAlignment="Left" Margin="350,520,0,0" VerticalAlignment="Top" Width="75" Click="myGetAnswer"/>
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="600,520,0,0" TextWrapping="Wrap" Text="Hello2" VerticalAlignment="Top"/>
</Grid>
</Window>
and
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication3
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void mySetQuestion(object sender, EventArgs e)
{
mshtml.HTMLDocument document = (mshtml.HTMLDocument)WebBrowser1.Document;
mshtml.IHTMLElement textArea = document.getElementById("myQuestion1");
textArea.innerHTML = "What is 1+1?";
}
private void myGetAnswer(object sender, EventArgs e)
{
mshtml.HTMLDocument document = (mshtml.HTMLDocument)WebBrowser1.Document;
mshtml.IHTMLElement textArea = document.getElementById("myStudentInput1");
textBlock.Text = textArea.innerHTML;
}
}
}
but it doesn't work.
I have no idea what that could possibly mean. All you can get is a code snippet that does work:
public partial class Form1 : Form {
private WebBrowser webBrowser1;
private Button button1;
public Form1() {
button1 = new Button { Text = "Test" };
button1.Click += button1_Click;
this.Controls.Add(button1);
webBrowser1 = new WebBrowser { Dock = DockStyle.Fill };
webBrowser1.DocumentText = #"<html><body><textarea class=""myStudentInput"" id=""myStudentInput1"">Text to be copied</textarea></body></html>";
this.Controls.Add(webBrowser1);
}
private void button1_Click(object sender, EventArgs e) {
var elem = webBrowser1.Document.GetElementById("myStudentInput1");
MessageBox.Show(elem.InnerText);
}
}
Which produces:

how to make tooltip move along with mouse?

I am using Silverlight 3 + VSTS 2008. I have a image (Multiscale image control) and I place tooltip on this image. The function of Tooltip works fine. Since the image is big (about 500 * 500 size), and since end user could move mouse on the picture, and I want to display tooltip position along with the mouse (i.e. when mouse moves, I want to tooltip move along with the mouse). Currently, the tooltip displays at a fixed position.
Here is my current XAML code, any ideas how to solve this issue?
<MultiScaleImage x:Name="msi" Height="500" Width="500">
<ToolTipService.ToolTip>
<ToolTip Content="Here is a tool tip" Name="DeepZoomToolTip"></ToolTip>
</ToolTipService.ToolTip>
</MultiScaleImage>
I ended up having a similar issue and solved the issue by using a popup. This post contained the core solution. Here is the suggested XAML from the other post:
<Canvas x:Name="LayoutRoot" Background="White">
<Image Source="/pretty-pretty.png" MouseMove="Image_MouseMove" MouseLeave="Image_MouseLeave"/>
<Popup Name="DeepZoomToolTip">
<Border CornerRadius="1" Padding="1" Background="Azure" IsHitTestVisible="False">
<TextBlock Text="Here is a tool tip" />
</Border>
</Popup>
</Canvas>
And here is the suggested, this would go in the code behind:
private void Image_MouseMove(object sender, MouseEventArgs e)
{
DeepZoomToolTip.IsOpen = true;
DeepZoomToolTip.HorizontalOffset = e.GetPosition(LayoutRoot).X;
DeepZoomToolTip.VerticalOffset = e.GetPosition(LayoutRoot).Y;
}
private void Image_MouseLeave(object sender, MouseEventArgs e)
{
DeepZoomToolTip.IsOpen = false;
}
The tooltip control is designed to pop up roughly where the mouse meets the element to which it's bound, and can't respond to move events. Below is a custom tooltip example. I added the background and the z-index so that the TextBlock would appear over the image. The offset from the mouse position keeps the tooltip away from the mouse cursor, so that the movement is animated smoothly.
XAML:
<UserControl x:Class="ImageEditor.TestControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="800" Height="800">
<Canvas x:Name="MainCanvas">
<Border x:Name="tt" Background="Gray" Visibility="Collapsed" Canvas.ZIndex="10">
<TextBlock x:Name="txtTooltip" Width="90" Height="20" Text="This is a tooltip" ></TextBlock>
</Border>
<Image x:Name="theImage" Source="images/image.jpg" Width="300" MouseEnter="theImage_MouseEnter"
MouseMove="theImage_MouseMove" MouseLeave="theImage_MouseLeave">
</Image>
</Canvas>
</UserControl>
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace ImageEditor
{
public partial class TestControl : UserControl
{
private bool _tooltipVisible = false;
public TestControl()
{
InitializeComponent();
}
private void theImage_MouseMove(object sender, MouseEventArgs e)
{
if (_tooltipVisible)
{
tt.SetValue(Canvas.TopProperty, e.GetPosition(theImage).Y - (5 + txtTooltip.Height));
tt.SetValue(Canvas.LeftProperty, e.GetPosition(theImage).X - 5);
}
}
private void theImage_MouseEnter(object sender, MouseEventArgs e)
{
_tooltipVisible = true;
tt.Visibility = Visibility.Visible;
}
private void theImage_MouseLeave(object sender, MouseEventArgs e)
{
_tooltipVisible = false;
tt.Visibility = Visibility.Collapsed;
}
}
}

Categories

Resources