WPF MVVM 交互绑定 CommandParameter 到 UI 元素

WPF MVVM Interaction Binding CommandParameter to UI element

我希望在 TextBox 获得焦点时选择 TextBox 中的文本。 因此,我需要将命令绑定到 "GotFocus" 事件。特别之处在于,TextBox 是通过 ItemsControl 动态创建的 。 因此存在到 UserControl (View)、ItemsControl 和 Item 本身的绑定。当我尝试将 UI 元素绑定到 CommandParameter 时,我刚刚将模型绑定到 ItemsControl 中的当前项目。

除了 CommandParameter..

之外的所有绑定都工作正常

有人知道如何让它工作吗?

这是我的代码:

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

型号

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; }
    }

由于你想做的只是与视图相关,我只是在代码隐藏中添加代码,而不是尝试使用命令并在 ViewModel 中获取 TextBox。在 MVVM 中,您永远不应从 ViewModel 引用 UI 程序集。但是,如果您尝试做的只是与视图相关,那么您可以使用代码隐藏。

因此,在 TextBox 的样式中,您将拥有:

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

然后在 UserControl 的代码隐藏中:

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

您的 DataTemplate 的完整代码将是:

<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>

请注意,在 GotFocus 事件上调用的 TextBox 的 SelectAll() 方法有一个小技巧可以按预期工作。检查这个 SO 问题:How to automatically select all text on focus in WPF TextBox?