WPF: Accessing children elements from a base class - wpf

I'm trying to create add some custom behaviors to a ScrollViewer in WPF / XAML. Specifically, the ScrollViewer should scroll to the top any time the Thumb in the VerticalScrollBar is clicked. Likewise, it should scroll to the left any time the Thumb in the HorizontalScrollBar is clicked.
I would think the easiest way of doing this would be to create a new class that inherits from ScrollViewer, and then subscribes to the MouseDoubleClick event on the VerticalScrollBar's Thumb and on the HorizontalScrollBar's Thumb.
For example:
public class DoubleClickScrollViwer : ScrollViewer
{
public DoubleClickScrollViwer()
: base()
{
//Find the Horizontal and Vertical scroll bars. Subscribe to the thumb's double click.
}
void VerticalScrollBarThumb_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
this.ScrollToTop();
}
void HorizontalScrollBarThumb_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
this.ScrollToLeft();
}
}
I can't seem to find a way to drill down to the children from the DoubleClickScrollViewer. How can I drill down to the children? Or is there a better way of going about this?

Related

WPF MouseDown event on FrameworkElement object

I have a WPF Application that receive FrameworkElement objects from 3rd party API.
I would like to register events on those objects.
Is this possible? This not working:
public void DisplayControl(FrameworkElement control)
{
control.MouseEnter += new MouseEventHandler(Control_MouseEnter);
control.MouseDown += new MouseButtonEventHandler(Control_MouseDownFromElement);
VideoGrid.Children.Add(control);
}
void Control_MouseDownFromElement(object sender, EventArgs e)
{
lblOutput.Content = string.Format("Sender is: " + sender.ToString());
}
void Control_MouseEnter(object sender, EventArgs e)
{
(sender as FrameworkElement).Focus();
}
One possible reason is the control provider is intentionally blocking that event... you can try adding a control(say grid) on the top of the original control with 0.01 opacity means virtually the control we have added is not visible to the user and we can write all the events on the invisible control...
Update
Something like this... create a grid with opacity 0.01 add events to that grid and add the grid to the video grid after adding your control... so in the video grid there will be control and on the top of the control there will be grid which is invisible because of its opacity and your events will work on the grid... make sure to give same height and width to the grid that match with your control height and width....
Grid grd = new Grid();
grd.Opacity = 0.01;
grd.MouseDown += new MouseButtonEventHandler(Grid_MouseDown_1);
VideoGrid.Children.Add(control);
VideoGrid.Children.Add(grd)

WPF Adorner appear on mouseover animation - what's the best pattern?

An Adorner is defined over part of an Image. The required behavior is as follows:
When the mouse is over the image area, including the Adorner area, the Adorner appears.
When the mouse leaves the image and Adorner area, the Adorner dissapears.
Adorner appearing and disappearing is to be through a fade in / out animation, accordingly.
A click on the Adorner area must raise event AdornerClicked
A click on the area over the Image which is not hidden by the adorner, must rais ImageClicked.
A naive implementation
Attach an animation on the Adorner opacity on the Image's MouseEnter and MouseLeave events, and attach Click events for each. This however causes the Adorner to disappear when the mouse is directly above it (as a MouseLeave is triggered on the Image below), violating requirement number 1.
A possible amendment to the naive implementation is to set IsHitTestVisible=false on the Adorner. However, no clicks are then captured by the Adorner, violating requirement number 4.
What is the correct pattern which will fulfill the requirements?
A bit old question but I've just had the same problem and could not find an answer so here's what I've come up with.
So the problem is that the control and its adorner are overlapping and setting the adorner to visible triggers a MouseLeave on the adorned control because it is now covered by the adorner.
The solution is to react on every MouseEnter and MouseLeave on both the adorned control and its adorner(s) and do a hit test manually. If any of them are hit then the adorner(s) should be visible otherwise collapsed.
So you need to be able to get the adorners from the adorned control and vica versa. Getting the adorned control from the adorner is no problem (use the AdornedElement property) but getting the adorners for a control is not provided by the framework (AFAIK) so I use a dictionary that maps my controls to a list of their adorners.
Here's the code inside my Panel-derived class (that contains and arranges my controls and their adorners):
private readonly Dictionary<Control, List<Adorner>> _controlToAdornersMap;
...
private void CreateMyControl()
{
var control = new MyControl();
control.MouseEnter += OnMyControlMouseEnterOrLeave;
control.MouseLeave += OnMyControlMouseEnterOrLeave;
Children.Add(control);
AddAdorners(control);
}
private void AddAdorners(Control control)
{
var myAdorner = new MyAdorner(control);
myAdorner.MouseEnter += OnMyAdornerMouseEnterOrLeave;
myAdorner.MouseLeave += OnMyAdornerMouseEnterOrLeave;
var adornerLayer = AdornerLayer.GetAdornerLayer(control);
adornerLayer.Add(myAdorner);
_controlToAdornersMap[control] = new List<Adorner> {myAdorner};
}
private void OnMyControlMouseEnterOrLeave(object sender, MouseEventArgs e)
{
HitTestAndSetAdornersVisibility((MyControl)sender, e);
}
private void OnMyAdornerMouseEnterOrLeave(object sender, MouseEventArgs e)
{
var adorner = (Adorner)sender;
HitTestAndSetAdornersVisibility((MyControl)adorner.AdornedElement, e);
}
private void HitTestAndSetAdornersVisibility(MyControl control, MouseEventArgs e)
{
var adorners = _controlToAdornersMap[control];
var hitTestSubjects = new List<UIElement> { control }.Concat(adorners);
var hit = hitTestSubjects.Any(i => VisualTreeHelper.HitTest(i, e.GetPosition(i)) != null);
SetAdornersVisibility(adorners, hit ? Visibility.Visible : Visibility.Collapsed);
}
private static void SetAdornersVisibility(IEnumerable<Adorner> adorners, Visibility visibility)
{
if (adorners != null)
foreach (var adorner in adorners)
adorner.Visibility = visibility;
}

Second Window Positioning WPF

I have MainWindow which has a button that allows it to open another WPF Window. I want this window to open always on the right hand side of the MainWindow practically right next to it.
How can I do this? This needs to work even if the width of the MainWindow changes as I have various buttons on the MainWindow that can change the size of the MainWindow depending on what panel is visible.
You can calculate where you want the new window if you have a reference to the other window.
Get the other windows position by accessing the Left and Top properties and its width by accessing the ActualWidth or the Width property.
Now you can calculate the new windows position by adding Left + Width + Some spacing.
Check out the documentation for the Left property here:
http://msdn.microsoft.com/en-us/library/system.windows.window.left.aspx
The others behave similarily.
You need to set manual startup location for second window in properties or in code:
WindowStartupLocation = WindowStartupLocation.Manual;
On events Loaded, SizeChanged, LocationChanged of first window, you should adjust position of second window like this:
public void AdjustPosition()
{
window2.Left = Application.Current.MainWindow.Left + Application.Current.MainWindow.ActualWidth;
window2.Top = Application.Current.MainWindow.Top;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
AdjustPosition();
}
private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
{
AdjustPosition();
}
void MainWindow_LocationChanged(object sender, EventArgs e)
{
AdjustPosition();
}

numericUpDown ValueChanged after MouseLeftButtonDown

I have 2 controls on a form. One numericUpDown (from the Silverlight Toolkit) and a simple Rectangle.
On the MouseLeftButtonDown of the Rectangle I popup a MessageBox with the numericUpDown value.
If I use the arrows to change the value of the numericUpDown, everyting is fine. But if I edit the value manually (with the keyboard) and immediately click on the Rectangle it shows the previous value of the numericUpDown. If I click a sencond time on the rectangle it will show the new value.
The numericUpDown.ValueChanged event is raised after the Rectangle.MouseLeftButtonDown event.
Is that a Silverlight bug? Anybody knows a workaround for that?
(btw I cannot change my Rectangle controls or events)
As workaround I propose you to create your own control like:
public class MyNumericUpDown : NumericUpDown
{
private TextBox _textBox;
public void Sync()
{
ApplyValue(_textBox.Text);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_textBox = (TextBox)GetTemplateChild("Text");
}
}
Now you can use method Sync to syncronize display text with control Value property. You can call method from XAML declaratively or in code behind. In your case:
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
myNumericUpDown.Sync();
MessageBox.Show(myNumericUpDown.Value.ToString());
}

RoutedEventArgs error

Basically a RoutedEvent travels through the Logical tree, either from top to bottom (Bubble event route) or bottom to top (Tunnel event route).
What this means is that if you have a Button inside of a StackPanel, that itself is inside of a Grid;
if you define a Click event in the controls they will all trigger it unless one of them handles it.
In my application I have:
Button -> StackPanel -> Grid
If it’s true, that StackPanel and Grid will not trigger it.
Grid -> StackPanel -> Button
if the Grid handles it, the StackPanel and Button will not trigger it.
in my application i wrote:
private void Button_Click(object sender, RoutedEventArgs e) {
Response.Redirect("http://www.legalbill.com");
}
it gave this-
Error - The name 'Response' does not exist in the current context …
what it means n how will i move to desired site?
Are you sure you are trying to do this in wpf ? If you are trying in silverlight,It doesn't support Response.Redirect.You can use like this
using System;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
namespace Tips
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// execute one of them.
HtmlPage.Window.Navigate(new Uri(“http://www.silverlight.net“));
HtmlPage.Window.Navigate(new Uri(“http://www.silverlight.net“), “_blank”);
HtmlPage.Window.Navigate(new Uri(“http://www.silverlight.net“), “_blank”, “toolbar=0″);
}
}
}

Resources