0
votes

I want the text in a TextBox to get selected when the TextBox gets focused. Therefore I need to binding a Command to the "GotFocus" event. The special thing is, that the TextBox is created dynamically via an ItemsControl. So there is a binding to the UserControl (View), the ItemsControl and the Item itself. When I tried to bind the UI element to the CommandParameter I just got the Model bindet to the current item in the ItemsControl.

All the bindings are working perfectly except the CommandParameter..

Somebody got an idea how to get this working?

Here is my code:

XAML

/////// <UserControl/> Information:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
x:Name="MainBindingControl"
///////

    <ItemsControl ItemsSource="{Binding MySecondModelList }" Margin="10,10,10,0">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid helper:GridHelper.RowCount="{Binding MyFirstModel.Rows}" helper:GridHelper.ColumnCount="{Binding MyFirstModel.Columns}">
                </Grid>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Grid.Row" Value="{Binding Row}" />
                <Setter Property="Grid.Column" Value="{Binding Column}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox Margin="25,25,25,25" Height="30" Width="30" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" TextAlignment="Center" VerticalContentAlignment="Center" >
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="GotFocus">
                            <i:InvokeCommandAction Command="{Binding ElementName=MainBindingControl, Path=DataContext.TextBoxFocusCommand}" CommandParameter="{Binding RelativeSource={ RelativeSource Self }}"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                <TextBox.Style>
                    <Style TargetType="TextBox">
                        <Setter Property="Background" Value="OrangeRed" />
                            <Style.Triggers>
                                <Trigger Property="Text" Value="0">
                                    <Setter Property="Background" Value="Orange" />
                                </Trigger>
                                <Trigger Property="Text" Value="1">
                                    <Setter Property="Background" Value="White" />
                                </Trigger>
                                <Trigger Property="Text" Value="2">
                                    <Setter Property="Background" Value="White" />
                                </Trigger>
                                <Trigger Property="Text" Value="3">
                                    <Setter Property="Background" Value="White" />
                                </Trigger>
                                <Trigger Property="Text" Value="4">
                                    <Setter Property="Background" Value="White" />
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </TextBox.Style>
                </TextBox>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

CS

    #region TextBoxFocus
    private ICommand _textBoxFocusCommand;
    public ICommand TextBoxFocusCommand
    {
        get { return _textBoxFocusCommand; }
        set { _textBoxFocusCommand = value; }
    }
    public void TextBoxFocus(object parameter)
    {
        var _tmp = parameter as TextBox;
        if (_tmp != null )
        {
            _tmp.SelectAll();
        }
    }
    #endregion

Models

public class FirstModel
    {
        public int Rows { get; set; }
        public int Columns { get; set; }
    }

public class SecondModel
    {
        public int Row { get; set; }
        public int Column { get; set; }
        public string Text { get; set; }
    }

public class ViewModel
    {
        public FirstModel MyFirstModel { get; set; }
        public ObservableCollection<SecondModel> MySecondModelList { get; set; }
    }
1
Why would you want an UI Element to be passed as a parameter to the ViewModel? This is not how MVVM works really. The ViewModel knows nothing about the View.Daniel Marques
If I don't know which TextBox got focused I can't set the Text ot this TextBox as selected. And because I have a dynamically created List auf TextBoxes I can't bind them to a "real" property. At least that's what I think about it.bene_rawr
And the ViewModel knows nothing about a special TextBox. Thats right. It just edits a random TextBox. So there is no conflict with MVVM. Isn't it?bene_rawr
Yes you can. Is your SecondModel represented in the view by those TextBoxes created dynamically? And you want to get the "Text" property of the model?Daniel Marques
No. As I said before, I want the TextBox.Text to get selected. It has nothing to do with the MySecondModel.Text at all - even though it is the same content.bene_rawr

1 Answers

0
votes

Since what you want to do is only related to the view, I'd just add the code in the code-behind, instead of trying to use commands and get the TextBox inside the ViewModel. In MVVM you should NEVER reference UI assemblies from the ViewModel. But it is ok for you to use code-behind if what you are trying to do is only related to the View.

So, inside the style of the TextBox, you would have:

<EventSetter Event="GotFocus" Handler="TextBox_GotFocus"/>

And then in the code-behind of the UserControl:

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    TextBox textBox = sender as TextBox;
    textBox.SelectAll();
}

The complete code of your DataTemplate would then be:

<DataTemplate>
    <TextBox Margin="25,25,25,25" Height="30" Width="30" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" TextAlignment="Center" VerticalContentAlignment="Center" >
        <!-- Just erase this block of code
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="GotFocus">
                <i:InvokeCommandAction Command="{Binding ElementName=MainBindingControl, Path=DataContext.TextBoxFocusCommand}" CommandParameter="{Binding RelativeSource={ RelativeSource Self }}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>-->
        <TextBox.Style>                            
            <Style TargetType="TextBox">
                <EventSetter Event="GotFocus" Handler="TextBox_GotFocus"/>
                <Setter Property="Background" Value="OrangeRed" />
                <Style.Triggers>
                    <Trigger Property="Text" Value="0">
                        <Setter Property="Background" Value="Orange" />
                    </Trigger>
                    <Trigger Property="Text" Value="1">
                        <Setter Property="Background" Value="White" />
                    </Trigger>
                    <Trigger Property="Text" Value="2">
                        <Setter Property="Background" Value="White" />
                    </Trigger>
                    <Trigger Property="Text" Value="3">
                        <Setter Property="Background" Value="White" />
                    </Trigger>
                    <Trigger Property="Text" Value="4">
                        <Setter Property="Background" Value="White" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>
</DataTemplate>

Notice that the method SelectAll() of the TextBox called on GotFocus event has a little trick to work as intended. Check this SO question: How to automatically select all text on focus in WPF TextBox?