In order to select all text in a textbox with a click in a WPF app as well as in an Elmish.WPF app, I can use this C#/XAML code:
file SettingsPage.xaml:
<TextBox ....some code... PreviewMouseLeftButtonDown="SelectAllText"> </TextBox>
file Settings.xaml.cs (code behind):
public partial class Settings : UserControl
{
public Settings() => InitializeComponent();
private void SelectAllText(object sender, MouseButtonEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null)
{
return;
}
if (!textBox.IsKeyboardFocusWithin)
{
textBox.SelectAll();
e.Handled = true;
textBox.Focus();
}
}
}
The code works as expected. But I would like to use F#/Elmish.WPF code instead of C# code.
I have tried to create the F# equivalent of the aforementioned code using cmdParam
- see below. But it does not work as expected - the text is selected and then it is immediately unselected. Why does it not work and what do I do wrong?
If you need to see more code than shown below, you can find the entire VS solution on GitHub.
file SettingsPage.xaml:
<TextBox .. some code ... >
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<i:InvokeCommandAction PassEventArgsToCommand="True" Command="{Binding TextBoxClicked}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
file Settings.fs:
module Settings =
//some code
type Msg =
| TextBoxClickedEvent
//some other messages
let castAs<'T when 'T : null> (o:obj) =
match o with
| :? 'T as res -> res
| _ -> null //TODO
let paramTextBoxClickedEvent (p: obj) =
let e = castAs<MouseButtonEventArgs>(p)
let sender = e.Source
let textBox = castAs<TextBox>(sender)
let e =
match textBox.IsKeyboardFocusWithin with
| true -> ()
| false ->
textBox.SelectAll()
e.Handled = true |> ignore
textBox.Focus() |> ignore
e
TextBoxClickedEvent
let update (msg: Msg) (m: Model) : Model * Cmd<Msg> =
match msg with
| TextBoxClickedEvent -> m, Cmd.none
//some other code
let bindings(): Binding<Model,Msg> list =
[
//some code
"TextBoxClicked" |> Binding.cmdParam paramTextBoxClickedEvent
]
What was wrong:
The equivalent of C# code e.Handled = true;
is not e.Handled = true
in F#, but e.Handled <- true
.
Answer:
The relevant function is now: `
let paramTextBoxClickedEvent (p: obj) =
let e = castAs<MouseButtonEventArgs>(p)
let sender = e.Source
let textBox = castAs<TextBox>(sender)
let e =
match textBox.IsKeyboardFocusWithin with
| true -> ()
| false ->
textBox.SelectAll()
e.Handled <- true
textBox.Focus() |> ignore
e
TextBoxClickedEvent
This code now works. It may give you more inside into how Binding.cmdParam works. Anyway, do consider Bent Tranberg's comment (related to C#/code behind and separation of logic) first before using the F#/Elmish.WPF solution.