0

I'm trying to add DataGrid with the feauture to auto add row in the last one. so if the row is filled by pressing Enter of Tab or clicked away a new Row should be inserted. This code worked 1 time with Visual Studio 2022 but right now it's not working.

<Windowxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:PasswordManager.Presse.content"xmlns:Collections="clr-namespace:System.Collections;assembly=System.Runtime"x:Class="PasswordManager.Presse.content.IpData_Window"mc:Ignorable="d"Title="Indirizzi IP" Height="400" Width="800" Icon="/icons/icons_ip_address_black_50x50.png" Background="{x:Null}"><Window.Resources><FontFamily x:Key="GemunuLibre">pack://application:,,,/font/GemunuLibre.ttf#Gemunu Libre</FontFamily><FontFamily x:Key="Abel">pack://application:,,,/font/Abel.ttf#Abel</FontFamily><FontFamily x:Key="FjallaOne">pack://application:,,,/font/FjallaOne.ttf#FjallaOne</FontFamily><FontFamily x:Key="Oswald">pack://application:,,,/font/Oswald.ttf#Oswald</FontFamily><FontFamily x:Key="Cairo">pack://application:,,,/font/Cairo.ttf#Cairo</FontFamily></Window.Resources>
<Border>
    <Border.Background>
        <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
            <GradientStop Color="#FFF7C295" Offset="0"/>
            <GradientStop Color="#FFFFCD73" Offset="1"/>
        </LinearGradientBrush>
    </Border.Background>

    <Grid Margin="0,10.5,0,0">

        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="6*"/>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0" Margin="0,3,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="1.4*"/>
            </Grid.ColumnDefinitions>

            <Grid Grid.Column="0">

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2.3*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <Grid Grid.Column="0">
                    <TextBox Margin="10,5,0,5" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" FontSize="18" Text="192.168.254.254" FontFamily="{DynamicResource Abel}" Padding="0,0,3,0"/>
                </Grid>

                <Grid Grid.Column="1">
                    <Label Content="Subnet" VerticalContentAlignment="Center" FontSize="18" FontFamily="{DynamicResource Oswald}"/>
                </Grid>

            </Grid>

            <Grid Grid.Column="1">

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2.3*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <Grid Grid.Column="0">
                    <TextBox Margin="10,5,0,5" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" FontSize="18" Text="192.168.254.254" FontFamily="{DynamicResource Abel}" Padding="0,0,3,0"/>
                </Grid>

                <Grid Grid.Column="1">
                    <Label Content="Router" VerticalContentAlignment="Center" FontSize="18" FontFamily="{DynamicResource Oswald}"/>
                </Grid>

            </Grid>

            <Grid Grid.Column="2">

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <Grid Grid.Column="0">
                    <TextBox Margin="10,5,0,5" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" FontSize="18" Text="192.168.254.254" FontFamily="{DynamicResource Abel}" Padding="0,0,3,0"/>
                </Grid>

                <Grid Grid.Column="1">
                    <Label Content="Subnet Teleassistenza" VerticalContentAlignment="Center" FontSize="18" FontFamily="{DynamicResource Oswald}"/>
                </Grid>

            </Grid>

        </Grid>

        <Grid Grid.Row="1" Margin="0,5,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>


        </Grid>

        <Grid Grid.Row="1" Cursor="" Margin="0,10,0,0">
            <DataGrid Name="DataGridIP" CanUserAddRows="True" AutoGenerateColumns="False" Margin="10,0,10,10" BorderBrush="Transparent" RowHeight="40" HorizontalAlignment="Stretch" CanUserResizeRows="False" CanUserResizeColumns="False" ItemsSource="{Binding IpData}">
                <DataGrid.Resources>
                    <!-- Usando il template definito sopra -->
                    <DataTemplate x:Key="row_1">
                        <Button Width="30" Height="30" BorderBrush="Transparent" OverridesDefaultStyle="True" FocusVisualStyle="{x:Null}" Cursor="Hand">
                            <Button.Template>
                                <ControlTemplate TargetType="Button">
                                    <Grid>
                                        <Image Source="/icons/icons_delete_3d_50x50.png" Width="30" Height="30"/>
                                    </Grid>
                                    <ControlTemplate.Triggers>
                                        <!-- Trigger per hover senza cambiare nulla -->
                                        <Trigger Property="IsMouseOver" Value="True">
                                            <Setter Property="Background" Value="Transparent"/>
                                            <Setter Property="BorderBrush" Value="Transparent"/>
                                        </Trigger>
                                        <!-- Trigger per il focus -->
                                        <Trigger Property="IsFocused" Value="True">
                                            <Setter Property="Background" Value="Transparent"/>
                                            <Setter Property="BorderBrush" Value="Transparent"/>
                                        </Trigger>
                                        <Trigger Property="IsPressed" Value="True">
                                            <Setter Property="Background">
                                                <Setter.Value>
                                                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                                        <GradientStop Color="#FFF7C69C"/>
                                                        <GradientStop Color="#FFE6FF01" Offset="1"/>
                                                    </LinearGradientBrush>
                                                </Setter.Value>
                                            </Setter>
                                            <Setter Property="BorderBrush" Value="Transparent"/>
                                        </Trigger>
                                    </ControlTemplate.Triggers>
                                </ControlTemplate>
                            </Button.Template>
                        </Button>
                    </DataTemplate>

                    <!-- Template per la Descrizione (TextBox per la modifica) -->
                    <DataTemplate x:Key="row_2">
                        <TextBox Text="{Binding Descrizione, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontFamily="{DynamicResource Abel}" FontSize="18" Margin="0,0,0,0" BorderBrush="Transparent" BorderThickness="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center" HorizontalScrollBarVisibility="Auto"/>
                    </DataTemplate>

                    <!-- Template per l'Indirizzo IP (TextBox per la modifica) -->
                    <DataTemplate x:Key="row_3">
                        <TextBox Text="{Binding IP, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontFamily="{DynamicResource Oswald}" FontSize="18" VerticalContentAlignment="Center" BorderBrush="Transparent" BorderThickness="0" HorizontalScrollBarVisibility="Auto"/>
                    </DataTemplate>

                </DataGrid.Resources>

                <DataGrid.Columns>
                    <!-- Colonna con il pulsante -->
                    <DataGridTemplateColumn Header="" Width="0.3*" CellTemplate="{StaticResource row_1}"/>

                    <!-- Colonna per la Descrizione (modificabile) -->
                    <DataGridTemplateColumn Header="Descrizione" Width="2*" CellTemplate="{StaticResource row_2}"/>

                    <!-- Colonna per l'Indirizzo IP (modificabile) -->
                    <DataGridTemplateColumn Header="Indirizzo IP" Width="*" CellTemplate="{StaticResource row_3}"/>
                </DataGrid.Columns>
            </DataGrid>

        </Grid>

    </Grid>

</Border>
</Window>
C# CODE:using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.ComponentModel;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Shapes;
namespace PasswordManager.Presse.content{/// <summary>/// Logica di interazione per IpData_Window.xaml/// </summary>public partial class IpData_Window : Window, INotifyPropertyChanged{public ObservableCollection<IPEntry> IpData { get; set; }
    public IpData_Window()
    {
        InitializeComponent();
        IpData = new ObservableCollection<IPEntry>();
        DataContext = this;
          
        DataGridIP.ItemsSource = IpData;
    }

    public class IPEntry
    {
        public string Descrizione { get; set; } = string.Empty;
        public string IP { get; set; } = string.Empty;

        // Costruttore vuoto richiesto dalla DataGrid per aggiungere nuove righe
        public IPEntry() { }
    }




    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

}
}

How i do i resolve or it's a bug? Thanks!!

the problem is that worked for 1 time!

1

1 Answer 1

1

Try reconfiguring your columns so that they have both a CellTemplate and a CellEditingTemplate as shown below. For debugging, I also find it helpful to monitor the editing state in the title bar of the main window. In my code example, as a matter of personal style, a textbox that receives focus will SelectAll() and also the Escape key action is made more immediate when editing a new record.


So, trying to stay as close as I can to the XAML you provided for the DataGrid:

<DataGrid 
    Name="DataGridIP" 
    CanUserAddRows="True"
    AutoGenerateColumns="False"
    Margin="10,0,10,10" 
    BorderBrush="Transparent"
    RowHeight="40" 
    HorizontalAlignment="Stretch"
    CanUserResizeRows="False"
    CanUserResizeColumns="False"
    ItemsSource="{Binding IpData}">
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Action" Width="80">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button
                        Width="30" 
                        Height="30"
                        BorderBrush="Transparent"
                        FocusVisualStyle="{x:Null}"
                        Cursor="Hand"
                        Click="OnActionButtonClick"
                        CommandParameter="{Binding .}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Description" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock 
                        Text="{Binding Descrizione}" 
                        FontFamily="{DynamicResource Abel}" 
                        FontSize="18"
                        VerticalAlignment="Center"
                        TextWrapping="Wrap"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <TextBox 
                        Text="{Binding Descrizione, UpdateSourceTrigger=PropertyChanged}"
                        FontFamily="{DynamicResource Abel}" 
                        FontSize="18"
                        BorderBrush="Transparent"
                        BorderThickness="0"
                        VerticalContentAlignment="Center"
                        HorizontalScrollBarVisibility="Auto"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="IP Address" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock 
                        Text="{Binding IP}" 
                        FontFamily="{DynamicResource Oswald}" 
                        FontSize="18"
                        VerticalAlignment="Center"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <TextBox
                        Text="{Binding IP, UpdateSourceTrigger=PropertyChanged}"
                        FontFamily="{DynamicResource Oswald}"
                        FontSize="18" 
                        BorderBrush="Transparent"
                        BorderThickness="0" 
                        VerticalContentAlignment="Center"
                        HorizontalScrollBarVisibility="Auto"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

Minimal New Item Flow Example

Using lambdas to subscribe to the DataGridIP events in the CTOR, one working implementation is shown below.

new MainWindowViewModel DataContext => (MainWindowViewModel)base.DataContext;
public MainWindow()
{
    InitializeComponent();
    DataGridIP.BeginningEdit += (sender, e) =>
    {
        Title = "Main Window - EDITING";
    };
    DataGridIP.CellEditEnding += (sender, e) =>
    {
        Title = "Main Window";
        switch (e.EditAction)
        {
            case DataGridEditAction.Cancel:
                if (e.Row.IsNewItem)
                {
                    DataContext.IpData.Remove((Record)e.Row.Item);
                    // Refresh the ephemeral row
                    DataGridIP.CanUserAddRows = false;
                    DataGridIP.CanUserAddRows = true;
                }
                break;
        };
    };
    DataGridIP.PreparingCellForEdit += (sender, e) =>
    {
        if (e.EditingElement is ContentPresenter cp)
        {
            cp.ApplyTemplate(); // Make sure the template elements exist.
            if(FindVisualChild<TextBox>(cp) is { } textBox)
            {
                Dispatcher.BeginInvoke(() =>
                {
                    textBox.SelectAll();
                    textBox.Focus();
                });
            }
        }
    };
    // Add test data items
    for (int i = 0; i < 3; i++)  DataContext.IpData.Add(new());
}

private void AnyTextBoxGotFocus(object? sender, RoutedEventArgs? e)
{
    if(sender is TextBox textBox)
    {
        Dispatcher.BeginInvoke(() =>
        {
            if (!DataContext.IsDataGridReadOnly)
            {
                textBox.SelectAll();
            }
            textBox.Focus();
        });
    }
}

private T? FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
{
    int childCount = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < childCount; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(parent, i);

        if (child is T foundChild)
        {
            return foundChild;
        }
        T? childOfChild = FindVisualChild<T>(child);
        if (childOfChild != null)
        {
            return childOfChild;
        }
    }
    return default;
}

Models

class MainWindowViewModel : INotifyPropertyChanged
{
    public ObservableCollection<Record> IpData { get; } = new();

    protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    public event PropertyChangedEventHandler? PropertyChanged;
}

[DebuggerDisplay("{Descrizione}")]
class Record
{
    static int _autoIncrement = 1;
    public string Descrizione { get; set; } = $"Record {_autoIncrement++}";
    public string? IP { get; set; } = "0.0.0.0";
}

As tracked in the title bar, clicking in the blank row now enters edit mode properly.

screenshot

Sign up to request clarification or add additional context in comments.

1 Comment

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.