Reputation: 707
I am new to WPF and have hit a wall trying to solve a seemingly straightforward problem.
I need to design a table of data and allow users to edit it. When user starts editing a cell I need to display a set of buttons in the rightmost column [OK] and [Cancel] to either accept or cancel the changes. When user is not editing a cell a [Delete] button should be displayed for user to delete the row.
I wrote a custom control that would display either [OK][Cancel] or a single [Delete] button based on the custom IsInEditMode property.
public partial class RowEditControl : UserControl
{
public static DependencyProperty
IsInEditModeProperty = DependencyProperty.Register( "IsInEditMode",
typeof(bool),
typeof(RowEditControl),
new FrameworkPropertyMetadata(OnEditModeChanged));
private static void OnEditModeChanged(DependencyObject aD, DependencyPropertyChangedEventArgs aE)
{
//depending on the value show [Delete] or [Ok][Cancel] buttons
}
}
I need to somehow set IsInEditMode when user starts editing a cell. I've been looking all over msdn and this forum for an example/way how to do it, but can't find anything.
I add my custom control to the last column programmatically like this:
{
mwTagList.Columns[1].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
var fRowEditTemplate = new FrameworkElementFactory(typeof (RowEditControl));
fRowEditTemplate.AddHandler(
RowEditControl.DeleteClickedEvent,
new RoutedEventHandler(OnDeleteRowBtn)
);
fRowEditTemplate.AddHandler(
RowEditControl.OkClickedEvent,
new RoutedEventHandler(OnRowEditOk));
fRowEditTemplate.AddHandler(
RowEditControl.CancelClickedEvent,
new RoutedEventHandler(OnRowEditCancel));
mwTagList.Columns.Add(
new DataGridTemplateColumn()
{
Header = "Delete Row",
CellTemplate = new DataTemplate() {VisualTree = fRowEditTemplate}
}
);
}
Thank you very much for any info and tips!
Upvotes: 1
Views: 1178
Reputation: 707
I solved this problem using styles:
<Style x:Key="MwControlCellStyle" TargetType="{x:Type notesList:RowEditControl}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<!-- find DataGridRow parent object and trigger if it is in editing mode -->
<Condition Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}, Path=IsEditing}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="IsInEditMode" Value="True"></Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
Upvotes: 2
Reputation: 76
There is an IsEditing dependency property on the DataGridRow so you can probably do this with XAML and a couple of converters. The main bits of the XAML look something like this
<Window.Resources>
<viewModel:BooleanVisibleConverter x:Key="boolVisConv"/>
<viewModel:InverseBooleanVisibleConverter x:Key="invBoolVisConv"/>
<DataTemplate x:Key="DataGridButtonsTemplate">
<StackPanel >
<Button Content="Delete" Visibility ="{Binding IsEditing, Mode=OneWay, Converter={StaticResource invBoolVisConv}, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGridRow}}"/>
<Button Content="OK" Visibility="{Binding IsEditing, Mode=OneWay, Converter={StaticResource boolVisConv},RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGridRow}}"/>
<Button Content="Cancel" Visibility="{Binding IsEditing, Mode=OneWay, Converter={StaticResource boolVisConv},RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGridRow}}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<DataGrid Grid.Row="1" ItemsSource="{Binding MyData}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding FirstField}" Header="First Property"></DataGridTextColumn>
<DataGridTextColumn Binding="{Binding SecondField}" Header="Second Property"></DataGridTextColumn>
<DataGridTextColumn Binding="{Binding ThirdField}" Header="Third Property"></DataGridTextColumn>
<DataGridTemplateColumn Header="Control" CellTemplate="{StaticResource DataGridButtonsTemplate}"></DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
An example converter is here, obviously you will need two of these, the second will have the return value reversed
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BooleanVisibleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (targetType != typeof(Visibility))
throw new InvalidOperationException("The target must be a System.Windows.Visibility");
return ((bool)value)? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
You will need to figure out which button was pressed as there are will be one per row. There are a couple of ideas as to how to do that here
WPF DataGrid - Button in a column, getting the row from which it came on the Click event handler
Upvotes: 1