点击按钮时添加了空白行

时间:2018-08-11 22:34:52

标签: c# wpf xaml datatemplate

在GridView中,我有三种状态

  1. 仅查看

  2. 编辑

  3. 添加

                                                          

我想单击网格中某处的按钮以插入新行。 所以我有

public ObservableCollection<gridDataModel> GridCollection { get; set; }
public void AddNewRow()
{
    GridCollection.Insert(0, new gridDataModel());
}

我的问题是我希望网格第一行中的列可以是文本框或下拉菜单。因此,当我插入新行时,我可以在文本框中填写数据,或者从下拉菜单中选择值。

我所做的是我自定义了列的模板。例如

<GridViewColumn Header="Databases" Width="498">
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding DbName}">
                        <TextBox.Style>
                            <Style TargetType="TextBox">
                                 <Style.Triggers>
                                      <DataTrigger Binding="{Binding ViewStatus" Value="Visible">
                                         <Setter Property="IsReadOnly"  Value="True" />
                                     </DataTrigger>
                                     <DataTrigger Binding="{Binding ViewStatus" Value="Visible">
                                         <Setter Property="IsReadOnly"  Value="False" />
                                     </DataTrigger>
                                     <DataTrigger Binding="{Binding AddStatus" Value="Visible">
                                         <Setter Property="IsReadOnly"  Value="True" />
                                     </DataTrigger>
                                 </Style.Triggers>
                            </Style>
                        </TextBox.Style>
                    </TextBox>                      
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>

在“查看状态”中,每个单元格都是只读的

在“编辑”状态下,仅读取某些列。其他可以编辑。

最困难的部分是添加状态。我只希望第一行(新添加的行)处于编辑状态。这意味着第一行可以编辑,其余行是只读的。

如何?

1 个答案:

答案 0 :(得分:0)

您可以在多个条件下使用MultiDataTrigger。使用MultiDataTrigger时,必须满足所有条件才能应用设置器(逻辑 AND )。

在您的情况下,您需要两个条件- RowIndex = 0 AddStatus = Visible
但是,当您添加另一行时,您需要以某种方式禁用旧行的触发器。

<Style.Triggers>
    <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
            <Condition Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Converter={StaticResource GetRowIndexConverter}}" Value="0" />
            <Condition Binding="{Binding AddStatus}" Value="Visible" />
        </MultiDataTrigger.Conditions>
        <MultiDataTrigger.Setters>
            <Setter Property="IsReadOnly" Value="True" />
        </MultiDataTrigger.Setters>
    </MultiDataTrigger>
</Style.Triggers>

和转换器

public class GetRowIndexConverter : IValueConverter
{
    /// <inheritdoc />
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var item = (ListViewItem)value;

        var listView = (ListView)ItemsControl.ItemsControlFromItemContainer(item);
        int index = listView.ItemContainerGenerator.IndexFromContainer(item);

        return index;
    }

    /// <inheritdoc />
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

编辑:
由于您确实需要为旧行禁用触发器(添加新行时), 您可以使用下面的解决方法。但是我会考虑使用其他解决方案,更优雅,而不是太过分(可能使用代码隐藏/行为)

1)为您的ListView(下面的MyListView)命名。

2)使用MultiBinding切换到MultiValueConverter

<DataTrigger Value="True">
    <DataTrigger.Binding>
        <MultiBinding Converter="{StaticResource MyMultiValueConverter}">
            <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}" />
            <Binding Path="AddStatus" />

            <!--Count is observable, so every time when collection gets modified system will re-trigger our multi-converter-->
            <Binding Path="Items.Count" ElementName="MyListView" />                                                        
        </MultiBinding>
    </DataTrigger.Binding>

    <Setter Property="IsReadOnly" Value="True" />
</DataTrigger>

3)MultiValueConverter

public class MyMultiValueConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var listViewItem = (ListViewItem)values[0];

        ListView listView = (ListView)ItemsControl.ItemsControlFromItemContainer(listViewItem);
        int index = listView.ItemContainerGenerator.IndexFromContainer(listViewItem);

        if (values[1] == DependencyProperty.UnsetValue)
        {
            /*i.e. Object1.Object2.AddStatus - if Object2 is null then binding will return UnsetValue */
            return false;
        }

        Visibility addStatus = (Visibility)values[1];

        return index == 0 && addStatus == Visibility.Visible;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Items.Count的新行ListView中添加时,将重新触发MultiValueConverter