C# 如何使用MVVM在另一个控件之间插入控件?

C# 如何使用MVVM在另一个控件之间插入控件?,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我想在光标所在的文本框下方插入一个控件: 我在MVVM中有此代码,文本框是动态创建的: <ItemsControl IsTabStop="False" ItemsSource="{Binding ListControls}"> <ItemsControl.ItemTemplate> <DataTemplate> <Grid HorizontalAlignment="Stretch">

我想在光标所在的文本框下方插入一个控件:

我在MVVM中有此代码,文本框是动态创建的:

<ItemsControl IsTabStop="False" ItemsSource="{Binding ListControls}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid HorizontalAlignment="Stretch">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <Label Grid.Column="0"  Content="{Binding RGN_INdex}" Margin="5,5,5,5" FontSize="14" VerticalContentAlignment="Center"/>
                <TextBox Style="{StaticResource blankColor}" Text="{Binding RGN}" Grid.Column="1" FontSize="14" VerticalContentAlignment="Center" Margin="0,5,0,5"/>
                <Label Grid.Column="2"  Content="RSN:" Margin="5,5,5,5" FontSize="14" VerticalContentAlignment="Center"/>
                <TextBox Style="{StaticResource blankColor}" Text="{Binding RSN}" Grid.Column="3" FontSize="14" VerticalContentAlignment="Center" Margin="0,5,0,5"/>
                <Label Grid.Column="4"  Content="SGN:" Margin="5,5,5,5" FontSize="14" VerticalContentAlignment="Center"/>
                <TextBox Style="{StaticResource blankColor}" Text="{Binding SGN}" Grid.Column="5" FontSize="14" VerticalContentAlignment="Center" Margin="0,5,0,5"/>
                <Label Grid.Column="6"  Content="SN:" Margin="5,5,0,5" FontSize="14" VerticalContentAlignment="Center"/>
                <TextBox Style="{StaticResource blankColor}" Text="{Binding SN}" Grid.Column="7" FontSize="14" VerticalContentAlignment="Center" Margin="0,5,5,5"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
当我将光标放在
文本框1
并按下按钮时,这将在列表中添加一项。然后,视图将填充另一个文本框

因此,在我看来,我将:

Textbox1 
Textbox3
Textbox2 
在我的XAML中,我有
RGN_索引
——这将保存所创建控件的索引

在我看来,当光标聚焦在控件中时,我需要获得
RGN\u索引。但是我怎么能做到呢?然后将其传递给命令,以便在找到
RGN\u索引后插入列表?但是如何获取所选文本框的
RGN\u索引


我是MVVM的新手,我不知道如何实现这一点。

没有简单的答案,但让我来指导您如何做到这一点

让我先添加缺失的代码:

using Prism.Mvvm;
public class Ctrl
{
    public int RGN_Index { get; set; }
    public string RGN { get; set; }
    public string RSN { get; set; }
    public string SGN { get; set; }
    public string SN { get; set; }
}

public class TheViewModel : BindableBase
{
    public ObservableCollection<Ctrl> ListControls { get { return _listControls; } set { SetProperty(ref _listControls, value); } }
    private ObservableCollection<Ctrl> _listControls;

    // Constructor
    public class TheViewModel()
    {
        ListControls = new ObservableCollection<Ctrl>()
        {
            new Ctrl() {RGN_Index=1,RGN="RGN1", RSN="RSN1",SGN="SGN1",SN="SN1" },
            new Ctrl() {RGN_Index=2,RGN="RGN2", RSN="RSN2",SGN="SGN2",SN="SN2" }
        };
    }

}
其次,当您获得光标焦点时,需要更新此选定索引。让我们在VM中定义ICommand:

// Here I am binding using Prism.Commands.DelegateCommand
public ICommand GotFocusCommand {get; private set;} = new Prism.Commands.DelegateCommand<int?>(GotFocus_Execute);
private void GotFocus_Execute(int? index)
{
   if(index != null)
      SelectedIndex = index.Value;
}
您可以注意到绑定需要
相对资源
项控件
数据上下文
。原因是
DataTemplate
DataContext
仅限于
ListControl
,并且
命令
不是在
ListControl
中定义的,而是在VM中定义的。您可以将命令改为静态,但我将跳过此步骤

第四,您必须具有要插入的按钮。因此,让我们首先在VM中定义命令:

private int SelectedIndex {get; set;} = -1; // only accessed internally, so private is good enough
public ICommand InsertCommand { get; private set; } = new Prism.Commands.DelegateCommand(InsertCommand_Execute);
private void InsertCommand_Execute()
{
   if (SelectedIndex > 0)
   {
      // Insert at the selected index. Note that the Ctrl inserted is just for example
      ListControls.Insert(SelectedIndex,
         new Ctrl()
         {
            RGN_Index = ++last_index, // or whatever
            RGN = $"RGN{last_index}", // or whatever
            RSN = $"RSN{last_index}", // or whatever
            SGN = $"SGN{last_index}", // or whatever
            SN = $"SN{last_index}" // or whatever
         });
   }
}
private int last_index = 2; // this is just example. You might not even need this.
然后将此命令绑定到xaml上的按钮:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

<TextBox Text="{Binding RGN}" Grid.Column="1">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="GotFocus">
      <i:InvokeCommandAction Command="{Binding Path=DataContext.GotFocusCommand, Mode=OneTime, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" CommandParameter="{Binding RGN_Index}"/>
    </i:EventTrigger>
  </i:Interaction.Triggers>
</TextBox>
<Button Content="Insert" Command="{Binding Path=InsertCommand, Mode=OneTime}"/>

完成了

需要考虑的事项:

  • 当你点击按钮时,你的光标肯定不再聚焦在文本框上了。这样行吗
  • 与第一个相关的是,始终记录最后一个聚焦的选定索引,因此,如果您单击文本框以外的任何内容,然后单击“插入”按钮,它仍然可以工作。这样行吗

  • 你所需要担心的就是在
    视图模型的
    列表控件中插入中间的第三项。是的,我就是这么想的。因此,我需要获取RGN_索引,以便知道应该在ViewModel列表中的何处添加项。您可以使用绑定observablecollection的默认collectionview来获取特定项的索引。然后可以插入较低的索引。您需要对上方或下方行的viewmodel进行引用。在下一行的datacontext中使用控件,而不是在两行之间使用控件。我可以澄清一件事吗,当您说“光标聚焦”时,是鼠标悬停(未单击任何内容)还是鼠标悬停(与所选项目类似)?只是一个旁注:请始终提供一个最小的示例(请参阅)。例如,XAML中的
    FontSize
    Margin
    实际上并不需要显示您的问题,它们只是夸大了示例,使其更难阅读。感谢您提供的解决方案。我用了你的主意。它成功了
    <Button Content="Insert" Command="{Binding Path=InsertCommand, Mode=OneTime}"/>