У меня есть сетка данных в моем приложении WPF.
Эта сетка данных привязана к ObservableCollection, которая называется OperationClasses, как определено ниже.
Тип OperationClass состоит из 3 свойств: Name, Start и End соответственно.
Я хотел бы знать, как добавить OperationClass в качестве строки сетки данных в DataGridList, щелкнув последнюю строку с текстом «новый класс операций», как показано на изображении в виде прикрепленного файла.
Изображение DataGrid с примерами значений:
После того, как конечный пользователь ввел имя, а также начальное и конечное значение, текст «новый класс операции» будет отображаться в следующей строке, которая является новой последней строкой.
Как я могу составить статический текст «новый класс операций» с объектами с привязкой к данным, перечисленными в DataGrid?
public ObservableCollection<OperationClass> OperationClasses
{
get
{
return _operationClasses;
}
set
{
SetProperty(ref _operationClasses, value);
}
}
Я попытался найти способ использовать CompositeCollection, чтобы составить объекты с привязкой к данным (OperationClass) и статический текст «Новый класс операций». Но я не смог преуспеть в текущем этапе ..
Почему бы просто не добавить кнопку под вашей сеткой данных с содержимым «новый класс операции»? Вы можете установить для datagrid CanUserAddRows false. Кнопка добавляет пустой элемент в наблюдаемую коллекцию и устанавливает фокус на первую ячейку.
Здравствуйте, текст «новый класс операций», где конечный пользователь может ввести новый класс операций. После того, как пользователь ввел новый класс операций, этот текст должен появиться в следующей строке, после чего пользователь может ввести новый класс операций. статический текст должен существовать как элемент строки таблицы данных в таблице данных.
Вам нужно указать DataTemplateSelector
, чтобы применить выделенный DataTemplate
к столбцу-заполнителю.
Прежде всего, необходимо включить элемент-заполнитель (или строку таблицы-заполнителя), установив DataGrid.CanUserAddRows
на true
. Значение по умолчанию равно true
, поэтому просто убедитесь, что вы явно не установили его на false
.
В следующем примере предполагается, что вы хотите, чтобы текст-заполнитель заполнил первый столбец. Однако вы можете следовать приведенному ниже шаблону, чтобы добавить текст-заполнитель для любого столбца.
Следуя вашему коду, в примере предполагается, что модель данных, используемая для заполнения DataGrid
, представляет собой OperationClass
с двумя вымышленными свойствами для создания двух столбцов:
OperationClass.cs
class OperationClass : INotifyPropertyChanegd
{
public string TextDataFirstColumn { get; set; }
public string TextDataSecondColumn { get; set; }
}
Сначала определите DataTemplateSelector
:
OperationClassTemplateSelector.cs
class OperationClassTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate { get; set; }
public DataTemplate PlaceholderTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
=> item switch
{
OperationClass _ => this.DefaultTemplate,
var dataItem when dataItem is not null => this.PlaceholderTemplate,
_ => base.SelectTemplate(item, container),
};
}
Второй шаг — явно определить шаблоны столбцов.
Важно определить столбец, который должен содержать текст-заполнитель, как DataGridTemplateColumn
. Это необходимо для того, чтобы разрешить назначение реализации DataTemplateSelector
.
В первом столбце строки-заполнителя будет отображаться «Добавить новый элемент...» в качестве текста-заполнителя:
<DataGrid ItemsSource = "{Binding OperationClassItems}"
AutoGenerateColumns = "False">
<DataGrid.Columns>
<DataGridTemplateColumn Header = "1st Column">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate DataType = "{x:Type local:OperationClass}">
<TextBox Text = "{Binding TextDataFirstColumn}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<!-- Instead of defining the CellTemplate explicitly,
we assign the CellTemplateSelector instead -->
<DataGridTemplateColumn.CellTemplateSelector>
<local:OperationClassTemplateSelector>
<local:OperationClassTemplateSelector.DefaultTemplate>
<DataTemplate DataType = "{x:Type local:OperationClass}">
<TextBlock Text = "{Binding TextDataFirstColumn}" />
</DataTemplate>
</local:OperationClassTemplateSelector.DefaultTemplate>
<local:OperationClassTemplateSelector.PlaceholderTemplate>
<DataTemplate>
<TextBlock Text = "Add new item..." />
</DataTemplate>
</local:OperationClassTemplateSelector.PlaceholderTemplate>
</local:OperationClassTemplateSelector>
</DataGridTemplateColumn.CellTemplateSelector>
</DataGridTemplateColumn>
<DataGridTextColumn Header = "2nd Column"
Binding = "{Binding TextDataSecondColumn}" />
</DataGrid.Columns>
</DataGrid>
Прежде всего, я хотел бы поблагодарить вас за ценный пост. Но у меня есть некоторые проблемы с операцией добавления нового элемента. Я определил проблемы, поделившись соответствующими изображениями, как показано ниже. После того, как пользователь ввел имя, а также начальное и конечное значение, текст «новый класс операции» должен отображаться в следующей строке, которая является новой последней строкой. Другими словами, свойства «Имя», «Начало» и «Конец» являются обязательными. столбцы, которые необходимо заполнить, чтобы заполнитель отображался в следующей строке. В дополнение к этому, хотя я могу выбрать новую строку заполнителя элемента в качестве выбранной строки, я не могу сделать это для записей с привязкой к данным. Я буду очень рад, если у вас будет возможность сообщить мне.
Перед добавлением нового товара
После добавления нового товара
Выбранная строка элемента привязки данных
Чтобы упростить задачу, я делюсь кодом xaml, как показано ниже.
<UserControl.Resources>
<ResourceDictionary>
<Style TargetType = "TabItem">
<Setter Property = "Header" Value = "{Binding DataContext.SelectedTreeItem.Name, Mode=OneWay}"></Setter>
</Style>
<Style TargetType = "DataGridCell">
<Setter Property = "BorderBrush" Value = "Gainsboro"></Setter>
<Setter Property = "BorderThickness" Value = "0"></Setter>
</Style>
<Style TargetType = "DataGridRow">
<Style.Triggers>
<Trigger Property = "ItemsControl.AlternationIndex" Value = "0">
<Setter Property = "Background" Value = "{StaticResource ContentBackgroundColorBrush}"/>
</Trigger>
<Trigger Property = "ItemsControl.AlternationIndex" Value = "1">
<Setter Property = "Background" Value = "White"/>
</Trigger>
<Trigger Property = "IsSelected" Value = "True">
<Setter Property = "Foreground" Value = "DarkBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<AdornerDecorator>
<Grid>
<DataGrid x:Name = "OperationClassDataGrid"
ItemsSource = "{Binding PlantMachine.OperationClasses, UpdateSourceTrigger=PropertyChanged}"
AlternationCount = "2"
CanUserAddRows = "True"
CanUserDeleteRows = "True"
CanUserReorderColumns = "False"
CanUserResizeColumns = "False"
CanUserSortColumns = "False"
AutoGenerateColumns = "False"
IsReadOnly = "False">
<DataGrid.Columns>
<DataGridTextColumn Visibility = "Hidden" Header = "{DynamicResource Plant.OperationClass.List.Header.Key}" Binding = "{Binding OperationKey}" Width = "Auto" SortDirection = "Ascending"/>
<DataGridTemplateColumn Header = "{DynamicResource Plant.OperationClass.List.Header.Name}">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate DataType = "{x:Type model:OperationClass}">
<TextBlock Text = "{Binding OperationName}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<!-- Instead of defining the CellTemplate explicitly,
we assign the CellTemplateSelector instead -->
<DataGridTemplateColumn.CellTemplateSelector>
<local:OperationClassTemplateSelector>
<local:OperationClassTemplateSelector.DefaultTemplate>
<DataTemplate DataType = "{x:Type model:OperationClass}">
<TextBox Text = "{Binding OperationName}" />
</DataTemplate>
</local:OperationClassTemplateSelector.DefaultTemplate>
<local:OperationClassTemplateSelector.PlaceholderTemplate>
<DataTemplate>
<TextBlock Text = "new operation class..." />
</DataTemplate>
</local:OperationClassTemplateSelector.PlaceholderTemplate>
</local:OperationClassTemplateSelector>
</DataGridTemplateColumn.CellTemplateSelector>
</DataGridTemplateColumn>
<DataGridTextColumn Header = "{DynamicResource Plant.OperationClass.List.Header.Start}" Binding = "{Binding RangeStartValue}" Width = "Auto" SortDirection = "Ascending"/>
<DataGridTextColumn Header = "{DynamicResource Plant.OperationClass.List.Header.End}" Binding = "{Binding RangeEndValue}" Width = "Auto" SortDirection = "Ascending"/>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source = "/Resources/Images/Delete.png" Width = "125" Height = "30" HorizontalAlignment = "Right">
<Image.InputBindings>
<MouseBinding Gesture = "LeftClick" CommandParameter = "{Binding Path=Key}" Command = "{Binding DataContext.RemoveOperationClassCommand, RelativeSource = {RelativeSource FindAncestor, AncestorType = {x:Type DataGrid}}}" />
</Image.InputBindings>
</Image>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</AdornerDecorator>
</UserControl>
Возможно, простое ContextMenu поможет?