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

时间:2018-04-23 07:34:31

标签: c# wpf xaml mvvm

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

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

例如,我有两个文本框:

Textbox1 
Textbox2 

当我将光标放在Textbox1并按下按钮时,这将在列表中添加一个项目。然后,视图将填充另一个文本框。

所以在我看来,我会有这个:

Textbox1 
Textbox3
Textbox2 

在我的XAML中,我有RGN_INdex - 这将保存创建的控件的索引。

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

我是MVVM的新手,我无法弄清楚如何使这项工作。

1 个答案:

答案 0 :(得分:1)

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

让我先添加缺少的代码:

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中当前关注的TextBox RGN_Index

private int SelectedIndex {get; set;} = -1; // only accessed internally, so private is good enough

其次,当您获得光标焦点时,需要更新此选定的索引。让我们在您的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;
}

然后,我们需要绑定TextBox&#39; GotFocus事件并传递RGN_Index作为参数。在你的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>

您可以注意到绑定需要RelativeSource ItemsControl DataContext。原因是DataTemplate DataContext仅限于ListControlCommand未在ListControl中定义,而是在VM中定义。您可以将命令设为静态,但我将跳过此步骤。

第四,你必须要插入按钮。所以,让我们首先在VM中定义命令:

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上的按钮:

<Button Content="Insert" Command="{Binding Path=InsertCommand, Mode=OneTime}"/>

完成!

需要考虑的事项:

  1. 当您单击该按钮时,光标肯定不再聚焦于文本框。这样好吗?
  2. 与第一个相关,始终记录最后一个聚焦选定索引,因此如果您单击文本框以外的任何内容,然后单击插入按钮,它仍然可以工作。这样好吗?