在GridView中,我有三种状态
仅查看
编辑
添加
我想单击网格中某处的按钮以插入新行。 所以我有
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>
在“查看状态”中,每个单元格都是只读的
在“编辑”状态下,仅读取某些列。其他可以编辑。
最困难的部分是添加状态。我只希望第一行(新添加的行)处于编辑状态。这意味着第一行可以编辑,其余行是只读的。
如何?
答案 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