Hook up right click events to all textbox in silverlight - silverlight

Is there anyway to add right click events to all textbox controls in silverlight without needing to manually adding it to each control in the whole project?
doing like:
<TextBox x:Name="txtName" MouseRightButtonUp="txtName_MouseRightButtonUp"
MouseRightButtonDown="txtName_MouseRightButtonDown" /></TextBox>
then fixing the events in the .cs for about 50+ (hopefully it's just 50+) textboxes can take a while.
If not then what might be the easiest way to do this?

You can extend your textbox
class SimpleTextBox
{
public SimpleTextBox()
{
DefaultStyleKey = typeof (SimpleCombo);
MouseRightButtonDown += OnMouseRightButtonDown;
}
private void OnMouseRightButtonDown(object sender, MouseButtonEventArgs
mouseButtonEventArgs)
{
//TODO something
}
}
==========
And use this control.
Or as alternative solution - you can create behavior:
CS:
...
using System.Windows.Interactivity;
public class TextBoxBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.MouseRightButtonDown += AssociatedObject_MouseRightButtonDown;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.MouseRightButtonDown -= AssociatedObject_MouseRightButtonDown;
}
private void OnMouseRightButtonDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
e.Handled = true;
// DO SOMETHING
}
}
XAML:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<TextBox ...>
<i:Interaction.Behaviors>
<local:TextBoxBehavior />
</i:Interaction.Behaviors>
</TextBox>
And attach this handler to your TextBox general style.

My answer to this question is also the answer to your question.
In short it's probably easiest to derive a type from TextBox, put your MouseRightButtonDown event handler in there and replace all existing instances of textBox with your type.

Related

Problem with same Blend behaviour applied to multiple elements

I created a simple Blend behaviour to be attached to TextBox elements. It's purpose is to scroll the textbox to its end when it gets the focus, and to scroll it back to the beginning when it loses the focus.
public class TextBoxScrollToEndBehaviour : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.GotFocus += AssociatedObject_GotFocus;
AssociatedObject.LostFocus += AssociatedObject_LostFocus;
}
private void AssociatedObject_LostFocus(object sender, System.Windows.RoutedEventArgs e)
{
var textBox = sender as TextBox;
textBox.ScrollToHorizontalOffset(0);
}
private void AssociatedObject_GotFocus(object sender, System.Windows.RoutedEventArgs e)
{
var textBox = sender as TextBox;
textBox.ScrollToHorizontalOffset(double.PositiveInfinity);
}
}
Xaml:
<TextBox Text="{Binding MyBinding, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Behaviors>
<behaviours:TextBoxScrollToEndBehaviour />
</i:Interaction.Behaviors>
</TextBox>
It works great when I focus the TextBox and then I click on some other control to loose the focus. Problem is that if I switch the focus between two TextBox that share the same behaviour, the scroll is not set back to 0 on the first TextBox, even the LostFocus event is correctly triggered on it.
What am I missing here? Thanks!
.NET Framework 4.7.2
I found out that by replacing this line in the LostFocus event:
textBox.ScrollToHorizontalOffset(0);
with
textBox.ScrollToLine(0);
the behaviour works perfectly in any condition.

How to route IsEnabledChanged (not routed event) to an EventHandler WPF

I'm simply trying to reset the value of a NumericUpDown element in xaml to 0 when IsEnabled becomes false, but checking for IsEnabled changes is not a routed event. This is what I currently have which doesn't work because this event is not a Routed Event
My XAML code:
<CheckBox Name="AirportTemplate">Airport</CheckBox>
<NumericUpDown Name="AirportToGen"
Width="300"
Minimum="0"
IsEnabled="{Binding ElementName=AirportTemplate, Path=IsChecked}"
IsEnabledChanged="ResetValueAirport"/>
My Code Behind C#
private void ResetValueAirport(object sender, EventArgs e)
{
if (!AirportToGen.IsEnabled)
{
AirportToGen.Value = 0;
}
}
I'm guessing you are using the NumericUpDown class form the extended WPF toolkit, in which case the IsEnabledChanged event requires a handler with the signature private void handler(object sender, DependencyPropertyChangedEventArgs e). So in your code behind use this instead:
private void ResetValueAirport(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
if (!AirportToGen.IsEnabled)
{
AirportToGen.Value = 0;
}
}

How to set focus on AND SELECT ALL of an initial text box (MVVM-Style)?

I have a simple WPF page with one text box field that my client wants highlighted when the page shows up. In code behind, it would be three lines, but I'm sogging through MVVM (which I'm starting to think is a little over-rated). I've tried so many different variants of behaviors and global events and FocusManager.FocusedElement, but nothing I do will do this.
Ultimately the most of the code I've been using calls these two lines:
Keyboard.Focus(textBox);
textBox.SelectAll();
But no matter where I put these lines the text box is only focused; no text is selected. I have never had this much trouble with something so simple. I've been hitting my head against the internets for two hours. Does anyone know how to do this?
Again, all I want to do is have the text box focus and it's text all selected when the page is navigated to. Please help!
"Focus" and "Select All Text from a TextBox" is a View-specific concern.
Put that in code Behind. It does not break the MVVM separation at all.
public void WhateverControl_Loaded(stuff)
{
Keyboard.Focus(textBox);
textBox.SelectAll();
}
If you need to do it in response to a specific application/business logic. Create an Attached Property.
Or:
have your View resolve the ViewModel by:
this.DataContext as MyViewModel;
then create some event in the ViewModel to which you can hook:
public class MyViewModel
{
public Action INeedToFocusStuff {get;set;}
public void SomeLogic()
{
if (SomeCondition)
INeedToFocusStuff();
}
}
then hook it up in the View:
public void Window_Loaded(Or whatever)
{
var vm = this.DataContext as MyViewModel;
vm.INeedToFocusStuff += FocusMyStuff;
}
public void FocusMyStuff()
{
WhateverTextBox.Focus();
}
See how this simple abstraction keeps View related stuff in the View and ViewModel related stuff in the ViewModel, while allowing them to interact. Keep it Simple. You don't need NASA's servers for a WPF app.
And no MVVM is not overrated, MVVM is extremely helpful and I would say even necessary. You'll quickly realize this as soon as you begin working with ItemsControls such as ListBoxes or DataGrids.
Here are some workthroughs:
Use Interaction.Behaviors
You can install the NuGet package named Microsoft.Xaml.Behaviors.Wpf, and write your own Behavior:
using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Controls;
public class AutoSelectAllBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.GotFocus += AssociatedObject_GotFocus;
}
private void AssociatedObject_GotFocus(object sender, RoutedEventArgs e)
{
if (AssociatedObject is TextBox box)
box.SelectAll();
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.GotFocus -= AssociatedObject_GotFocus;
}
}
and attach this behavior to the TextBox in the xaml:
<!-- xmlns:i="http://schemas.microsoft.com/xaml/behaviors" -->
<TextBox>
<i:Interaction.Behaviors>
<br:AutoSelectAllBehavior />
</i:Interaction.Behaviors>
</TextBox>
Use Interaction.Triggers
This is in the same package as mentioned in the last section. This special can be considered to let you be able to bind UIElement events to your ViewModel.
In your ViewModel, suppose you have an ICommand relay command (You may also need Microsoft.Toolkit.MVVM so that you can use some handy relay commands):
public ICommand SelectAllCommand { get; }
public ViewModel()
{
SelectAllCommand = new RelayCommand<TextBox>(box => box.SelectAll());
}
and then attach this command to the TextBox by setting the triggers:
<TextBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding SelectAllCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=TextBox}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
Use Attached Property
You can also use attached property (write your own class derived from TextBox and use dependency property is quite similar):
using System.Windows;
using System.Windows.Controls;
public class TextBoxProperties
{
public static bool GetAutoSelectAll(DependencyObject obj)
{
return (bool)obj.GetValue(AutoSelectAllProperty);
}
public static void SetAutoSelectAll(DependencyObject obj, bool value)
{
obj.SetValue(AutoSelectAllProperty, value);
}
public static readonly DependencyProperty AutoSelectAllProperty =
DependencyProperty.RegisterAttached("AutoSelectAll", typeof(bool), typeof(TextBoxProperties), new PropertyMetadata(false, TextBoxProperties_PropertyChanged));
private static void TextBoxProperties_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
if (d is TextBox box)
{
box.GotFocus += TextBox_GotFocus;
}
}
}
private static void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
var box = sender as TextBox;
box.SelectAll();
}
}
Then you can use it like:
<!-- xmlns:ap="..." -->
<TextBox ap:TextBoxProperties.AutoSelectAll="True" />

MVVM C# WPF binding mouse double click

I want to copy the content of one text box to another text box by clicking the mouse.
How do I bind a mouse click event?
This sample is for RightClick, but you can adjust the event according to your needs:
<TextBox>
<TextBox.InputBindings>
<MouseBinding Gesture="RightClick" Command="{Binding YourCommand}" />
</TextBox.InputBindings>
</TextBox>
Edit: I uploaded on my SkyDrive a sample app that illustrates how to use this method in order to achieve exactly what you need. Please be advised that it will only work for .NET Framework 4+
Want to add a behavior to a control ? Just use the Ramora pattern !
Hope this helps
Use this code for TreeView
<TreeView commandBehaviors:MouseDoubleClick.Command="{Binding YourCommand}"
commandBehaviors:MouseDoubleClick.CommandParameter="{Binding}"
.../>
Use this code for TreeViewItem
<TreeView ItemsSource="{Binding Projects}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="commandBehaviors:MouseDoubleClick.Command"
Value="{Binding YourCommand}"/>
<Setter Property="commandBehaviors:MouseDoubleClick.CommandParameter"
Value="{Binding}"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Use this code to create a new behavior MouseDoubleClick
public class MouseDoubleClick
{
public static DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command",
typeof(ICommand),
typeof(MouseDoubleClick),
new UIPropertyMetadata(CommandChanged));
public static DependencyProperty CommandParameterProperty =
DependencyProperty.RegisterAttached("CommandParameter",
typeof(object),
typeof(MouseDoubleClick),
new UIPropertyMetadata(null));
public static void SetCommand(DependencyObject target, ICommand value)
{
target.SetValue(CommandProperty, value);
}
public static void SetCommandParameter(DependencyObject target, object value)
{
target.SetValue(CommandParameterProperty, value);
}
public static object GetCommandParameter(DependencyObject target)
{
return target.GetValue(CommandParameterProperty);
}
private static void CommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
Control control = target as Control;
if (control != null)
{
if ((e.NewValue != null) && (e.OldValue == null))
{
control.MouseDoubleClick += OnMouseDoubleClick;
}
else if ((e.NewValue == null) && (e.OldValue != null))
{
control.MouseDoubleClick -= OnMouseDoubleClick;
}
}
}
private static void OnMouseDoubleClick(object sender, RoutedEventArgs e)
{
Control control = sender as Control;
ICommand command = (ICommand)control.GetValue(CommandProperty);
object commandParameter = control.GetValue(CommandParameterProperty);
command.Execute(commandParameter);
}
}
It sounds like you are inventing a new behaviour for your textbox :)
I would just consider if the users of your program understands and likes this behaviour.
Maybe it is easier to understand the funcionality if it is just a button you have to click - it is also faster to implement :)
I think you could bind mouse gestures to commands. Take a look at this: http://www.thejoyofcode.com/Invoking_a_Command_on_a_Double_Click_or_other_Mouse_Gesture.aspx
I'm not sure what exactly you're wanting to bind to.
There is no readily available MouseClick event as far as i'm aware.
the Click event as you'd find on a Button is inherited from ButtonBase and is not readily available on most controls.
MouseDoubleClick is inherited from Control and available on anythning deriving from it.
in your example it sounds like a simple Button with its Click event handled might do the trick.
To bind to the click event, you just need to specify the event handler for the event in the Button.
Something like:
XAML:
<TextBox Name=TextBoxOne />
<TextBox Name=TextBoxTwo />
<Button Click="CopyTextButton_Click"/>
And in your code behind:
void CopyTextButton_Click(object sender, RoutedEventArgs e)
{
//Copy the text and anything else you need done
}
Otherwise if this is a more specialised scenario, you might want to investigate using a UserControl or as AndrewS answered above, a Command.
Hope it helps.
You can easily do this by creating a new behavior.
<TextBox
MouseDoubleClick="SelectAddress"
GotKeyboardFocus="SelectAddress"
PreviewMouseLeftButtonDown="SelectivelyIgnoreMouseButton" />
Here's the code behind:
private void SelectAddress(object sender, RoutedEventArgs e)
{
TextBox tb = (sender as TextBox);
if (tb != null)
{
tb.SelectAll();
}
}
private void SelectivelyIgnoreMouseButton(object sender,
MouseButtonEventArgs e)
{
TextBox tb = (sender as TextBox);
if (tb != null)
{
if (!tb.IsKeyboardFocusWithin)
{
e.Handled = true;
tb.Focus();
}
}
}
Please update this snippet according to your need.

WPF ListView Show selected item

I want to show the selected item in a list view automatically(it isn't possible to show all items without scrolling).
this.listView.SelectedIndex = 999; selects of course an item, but it doesn't show it.
what can I use to show it automatically ?
kind regards, jeff
You can do this:-
listview.ScrollIntoView(listview.SelectedItem);
Scroll WPF ListBox to the SelectedItem set in code in a view model
Install a nuget package System.Windows.Interactivity.WPF, create a class like following:
public class ScrollToSelectedListBoxItemBehaviour: Behavior<ListBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectionChanged += AssociatedObjectOnSelectionChanged;
AssociatedObject.IsVisibleChanged += AssociatedObjectOnIsVisibleChanged;
}
protected override void OnDetaching()
{
AssociatedObject.SelectionChanged -= AssociatedObjectOnSelectionChanged;
AssociatedObject.IsVisibleChanged -= AssociatedObjectOnIsVisibleChanged;
base.OnDetaching();
}
private static void AssociatedObjectOnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
ScrollIntoFirstSelectedItem(sender);
}
private static void AssociatedObjectOnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
ScrollIntoFirstSelectedItem(sender);
}
private static void ScrollIntoFirstSelectedItem(object sender)
{
if (!(sender is ListBox listBox))
return;
var selectedItems = listBox.SelectedItems;
if (selectedItems.Count > 0)
listBox.ScrollIntoView(selectedItems[0]);
}
}
Add this behavior class to the xaml:
<ListView ItemsSource="{Binding Items}">
<i:Interaction.Behaviors>
<behaviors:ScrollToSelectedListBoxItemBehaviour />
</i:Interaction.Behaviors>
</ListView>
Check out this one:
Scroll WPF Listview to specific line
This might help you, i'm not sure if it's what you're looking for but it brings the selected item into view and scrolls to it for you if necessary.
int selectedIndex = listView.Items.IndexOf((listView.SelectedItems[0]))
listView.Items[selectedIndex].EnsureVisible();

Resources