WPF DataGrid SelectedItem

I have a DataGrid, the user can add elements by entering data in the last row. I also have a button that deletes the currently selected item. But when the last (empty, to add new elements) row is selected, everything that was the last selected element remains in the SelectedItem. Therefore, if I open the window, select the last row and click the "Delete" button, it will delete the first row, because it is selected by default, and the last row did not change SelectedItem. Any good way to handle this?

To clarify: SelectedItem = "{Binding X}"

X in the ViewModel does not change when the last row is selected (the setter is not involved at all). I'm not sure if the SelectedItem property has changed, but I would suggest that it is not.

There is also an exception when I select the last line (red frame), but when I click it again to start entering data, the red frame disappears. Not sure if the two are related.

+5
source share
3 answers

Run the following example and you will see why it does not work.

XAML:

<Window x:Class="DataGridTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel>
        <TextBlock DockPanel.Dock="Bottom" Text="{Binding SelectedItem, ElementName=dataGrid}"/>
        <TextBlock DockPanel.Dock="Bottom" Text="{Binding SelectedItem}"/>
        <DataGrid x:Name="dataGrid" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" CanUserAddRows="True" CanUserDeleteRows="True" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
                <DataGridTextColumn Header="Last Name" Binding="{Binding FirstName}"/>
            </DataGrid.Columns>
        </DataGrid>
    </DockPanel>
</Window>

Code for:

namespace DataGridTest
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Windows;

    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private readonly ICollection<Person> items;
        private Person selectedItem;

        public MainWindow()
        {
            InitializeComponent();

            this.items = new ObservableCollection<Person>();
            this.items.Add(new Person
                {
                    FirstName = "Kent",
                    LastName = "Boogaart"
                });
            this.items.Add(new Person
            {
                FirstName = "Tempany",
                LastName = "Boogaart"
            });

            this.DataContext = this;
        }

        public ICollection<Person> Items
        {
            get { return this.items; }
        }

        public Person SelectedItem
        {
            get { return this.selectedItem; }
            set
            {
                this.selectedItem = value;
                this.OnPropertyChanged("SelectedItem");
            }
        }

        private void OnPropertyChanged(string propertyName)
        {
            var handler = this.PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class Person
    {
        public string FirstName
        {
            get;
            set;
        }

        public string LastName
        {
            get;
            set;
        }

        public override string ToString()
        {
            return FirstName + " " + LastName;
        }
    }
}

As you can see at startup, selecting a “new” line causes the time zone value to be set as the selected item in DataGrid. However, WPF cannot convert this checkpoint element to Person, so the binding SelectedItemcannot convert.

, , , null . , :

namespace DataGridTest
{
    using System;
    using System.Windows.Data;

    public sealed class SentinelConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null && string.Equals("{NewItemPlaceholder}", value.ToString(), StringComparison.Ordinal))
            {
                return null;
            }

            return value;
        }
    }
}

, ToString() , . ( ) , GetType().Name NamedObject.

+10

, .

, , , , ViewModel null. , SelectedItem .

0

, , OneWay. , , , .

And always make sure you have the correct datacontext.

Hope this helps.

0
source

All Articles