TextBox and default Button binding does update too late - wpf

I've got a simple WPF dialog with these two controls:
<TextBox Text="{Binding MyText}"/>
<Button Command="{Binding MyCommand}" IsDefault="True"/>
Now, when I enter some text in the TextBox and click the button using the mouse, everything works like expected: the TextBox will set MyText and MyCommand is called.
But when I enter some text and hit enter to "click" the default button, it does not work. Since on hitting enter the focus does not leave the TextBox, the binding will not be refresh MyText. So when MyCommand is called (which works), MyText will contain old data.
How do I fix this in MVVM? In classic code-behind I probably just would call "MyButton.Focus()" in the MyCommand handler, but in MVVM the MyCommand handler does know nothing about the button.
So what now`?

Add the UpdateSourceTrigger to your TextBox with the value PropertyChanged. The default behavior of the Textbox is to update the source, when it´s lost focus.
<TextBox Text="{Binding MyText, UpdateSourceTrigger=PropertyChanged}"/>

Try this. This code moves focus on the button clicked. Thus binding completes before command processed.
public App()
{
EventManager.RegisterClassHandler(typeof(Button), Button.ClickEvent, new RoutedEventHandler(GenericButtonClickHandler));
}
void GenericButtonClickHandler(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button == null)
return;
if (button.IsDefault)
button.Focus();
}

One Solution ist, to create your own Class OKButton that calls Me.Focus in the OnClick-Method. This will be called before the Click_Event and before any Command that is bound to the button. You just have to remember to use an OKButton instead of setting IsDefault=True
Public Class OKButton
Inherits System.Windows.Controls.Button
Public Sub New()
MyBase.New()
Me.Content = "OK"
Me.IsDefault = True
End Sub
Protected Overrides Sub OnClick()
Me.Focus()
MyBase.OnClick()
End Sub
End Class

Related

How to get name of element with focus in WPF

I'm building a Mahjong game that has more buttons than Sgt. Pepper's band. The movement of the tile is simulated by showing the background of the button (tile) in question. I'd like to leverage the use of x:Name="button"and have only one click event, than 200 but the problem is in getting the name of the focused button. I can get the element with the focus but can not access the name property, if I could I would save a lot of inelegant drudgery. Here's what I'd like to do;
Private Sub b15_Click(sender As Object, e As RoutedEventArgs) Handles b15.Click
Dim brush As Brush
Dim vButton As Button
Dim InputElement As IInputElement = Keyboard.FocusedElement
vButton.Name = InputElement.name '!! here's the problem !!
If vTog = 0 Then 'background brush transferred from
brush = vButton.Background
vButton.Background = Nothing
vTog = 1
Else 'background brush transferred to
vButton.Background = brush
vTog = 0
End If
End Sub
Maybe I've missed an easy way to get the button's name so I can use it directly in the code behind. Thank you.
I recommend learning more about the basics of WPF.
As well as "regular" events WPF has routed events. See the signature of your click handler? Notice Routedeventargs rather than eventargs?
That click event is a routed event.
Routed events bubble ( up the visual tree ) and or tunnel (down the visual tree).
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/routed-events-overview
Because of this mechanism, you can handle a click event of buttons at a container further up the visual tree. That could be a grid, stackpanel or window.
In the handler, cast the originalsource of the event to button and that will have a name property.
I do c# but there is very little code to this and if you have trouble following it then you could put it through an online code converter.
Markup:
Title="MainWindow"
ButtonBase.Click="Window_Button_Click"
>
<StackPanel>
<Button Name="b1" Content="b1"/>
<Button Name="b2" Content="b2"/>
<Button Name="b3" Content="b3"/>
</StackPanel>
</Window>
Handler in code behind:
private void Window_Button_Click(object sender, RoutedEventArgs e)
{
Button btn = e.OriginalSource as Button;
if(btn!=null)
{
Debug.WriteLine(btn.Name ?? "No Name for this button");
}
}
If I spin that up with an f5, I see the name of each button clicked output to my output window when I click on them.
As an aside.
I'm not clear what the player clicks and what that does.
Maybe this could work in a generic way and the datacontext of each button would be a viewmodel holding x,y location or some such.

Text changed event of text box in a gridview

I am new in wpf, so i have a problem in my gridview.
I'm using a TextBox in the GridView . Basically, what I want to do is call a method every time the text in the box is edited. That is when the text is entered, the function will call. That is the text change event should work.
Use the TextChanged event.
.xaml:
<TextBox TextChanged="TextBox_TextChanged" ... />
.xaml.cs:
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
string text = ((TextBox)sender).Text;
// call your function
}

Silverlight: Copy/Paste Context Menu with TextBox (Text Highlighting Issue)

I have created a TextBox control:
public class MyTextbox : TextBox
which is a just a normal TextBox, to which I have added a behavior that I have written:
public class TextBoxCutCopyPasteBehavior : Behavior<TextBox>
Everything works fine and dandy: right-clicking will display a ContextMenu with Cut, Copy, Paste options. However, the TextBox text ceases to be highlighted at that point, since the TextBox has lost focus.
What would the best way be to make the selected text remain highlighted, even after the ContextMenu appears and the TextBox loses focus?
Thank you so much for all of your help!
You should still be able to access the SelectedText property of the TextBox
private void CopyMenuItem_Click(object sender, RoutedEventArgs e)
{
string textToCopy = MyTextBox.SelectedText;
// do something
}

WPF UserControl with TextBox, use TextChanged event C#

I have a customer usercontrol that is a labeled TextBox (Border wrapped about a Label and a TextBox with the TextBox overlapping the label). I am finding few (working) examples on how to get the TextChanged function to work when called from my UserControl.
Just the textbox snippet:
<TextBox
FontSize="{Binding Path=DefaultFontSize}"
Style="{StaticResource WatermarkTextBox}"
Padding="{Binding Path=TextPadding}"
Tag="{Binding Path=TextValue}"
/>
I have tried using RoutedEventHandler like I did with my button's Click event, but it didn't work. How do I get it so when let's say I use on the window it is required:
<MyControl:LabeledTextBox
TextBoxChange="Some_Event"
TextValue="{Binding SomethingOrOther}"
/>
that it will fire off correctly and do the needed function
This question's really unclear. Do you want your user control to support a TextChanged event that gets raised when the text in the TextBox changes? If so, you need to implement it in the code-behind.
First, declare the event:
public event TextChangedEventHandler TextChanged;
Then, add an event handler to the TextBox:
<TextBox TextChanged="TextBox_TextChanged" ... />
and in the code-behind:
private void TextBox_TextChanged(object sender, TextChangedEventArgs args)
{
TextChangedEventHandler h = TextChanged;
if (h != null)
{
h(this, args);
}
}
If you are using MVVM (Or if your TextValue binding is binding to something you can get to and edit) you can put the logic you want executed in the setter.
So, lets say you are binding to a property MyTextBoxValue. Set the binding mode to two way in the XAML, and in the setter put the logic or call to another method.
If you want the code to fire every time you type, set UpdateSourceTrigger=PropertyChanged in XAML, if you want the code to fire only when text entry is "done" set UpdateSourceTrigger=LostFocus.

WPF ICommand over a button

I have implemented a custom IComand class for one of my buttons. The button is placed in a page 'MyPage.xaml' but its custom ICommand class is placed in another class, not in the MyPage code behind. Then from XAML I want to bind the button with its custom command class and then I do:
MyPage.xaml:
<Page ...>
<Page.CommandBindings>
<CommandBinding Command="RemoveAllCommand"
CanExecute="CanExecute"
Executed="Execute" />
</Page.CommandBindings>
<Page.InputBindings>
<MouseBinding Command="RemoveAllCommand" MouseAction="LeftClick" />
</Page.InputBindings>
<...>
<Button x:Name="MyButton" Command="RemoveAllCommand" .../>
<...>
</Page>
and the custom command button class:
// Here I derive from MyPage class because I want to access some objects from
// Execute method
public class RemoveAllCommand : MyPage, ICommand
{
public void Execute(Object parameter)
{
<...>
}
public bool CanExecute(Object parameter)
{
<...>
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
My problem is how to say MyPage.xaml that Execute and CanExecute methods for the button is in another class and not the code behind where is placed the button. How to say these methods are in RemoveAllCommand Class in XAML page.
Also I want to fire this command when click mouse event is produced in the button so I do an input binding, is it correct?
Thanks
Since you have an ICommand, you can bind it to the Button through the Command property, and the button will use it, i.e. it will call CanExecute to enable/disable itself and the Execute method when the button is pressed. There is no need for any other input binding.
Now the problem is that the button has to find the command. A simple solution is to put an instance of the command in the DataContext of the button (or of its parents).
If the DataContext has a property called RemoveAll of type RemoveAllCommand, you can simply change your XAML button to:
<Button Command="{Binding RemoveAll}" .. />
and remove the CommandBinding and InputBinding
oK, Thanks, tomorrow I'll try it.
Now to avoid problems I have moved all in RemoveAllCommandClass Class to the code behind of MyPage and I have done some modifications.
1.- I added this to MyPage.xaml:
xmlns:local="clr-namespace:GParts"
then I have done:
<Page.CommandBindings>
<CommandBinding Command="{x:Static local:Pages.MyPage._routedCommand}"
Executed="Execute"
CanExecute="CanExecute"/>
</Page.CommandBindings>
<Button Command="{x:Static local:Pages.MyPage._routedCommand}" .../>
And all is ok and works. When I press button it executes background worker (bw) that is called in Execute method. bw is into another class. In background worker class I have a variable (isRunning) that indicates if the bw is executing. Before executing DoWork event I set it to true and when bw completes, at RunWorkerCompleted, I set it to false. So from CanExecute I check isRunning in bw class and I set to true e.canExecute if isRunning is false, and e.canExecute to false if isRunning is true. So the button is disabled by WPF automatically when bw is running but when bw finishes the button continues disabled and not returns to enabled until I press it again. Why is WPF not updating the button state to enabled when bw finishes until I press again the button?
Thanks.

Resources