1

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!

2 Answers 2

2

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>
Sign up to request clarification or add additional context in comments.

Comments

1

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

1 Comment

Thanks! I solved this problem using styles as above, but this looks cool too. It is also a great example on how to use converters, I am new to WPF and never used them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.