2012-02-02 38 views
5

Tôi có một DataGrid người dùng có thể thêm các mục vào bằng cách nhập dữ liệu vào hàng cuối cùng. Tôi cũng có một nút xóa mục hiện đang được chọn. Nhưng khi hàng cuối cùng (trống, để thêm mục mới) được chọn, bất kỳ mục nào được chọn cuối cùng vẫn còn trong SelectedItem. Vì vậy, nếu tôi mở cửa sổ, chọn hàng cuối cùng, và nhấn nút xóa, nó sẽ xóa hàng đầu tiên, vì nó được chọn theo mặc định và chọn hàng cuối cùng không thay đổi SelectedItem. Bất kỳ cách nào tốt để đối phó với điều này?WPF DataGrid SelectedItem

Để làm rõ: SelectedItem = "{Binding X}"

X trong ViewModel không thay đổi khi hàng cuối cùng được chọn (setter không gọi gì cả). Tôi không chắc liệu bản thân tài sản SelectedItem có thay đổi hay không, nhưng tôi cho rằng nó không có.

Ngoài ra còn có một ngoại lệ khi tôi chọn hàng cuối cùng (đường viền màu đỏ), nhưng khi tôi bấm lại nó để bắt đầu nhập dữ liệu, đường viền màu đỏ sẽ biến mất. Không chắc chắn nếu hai có liên quan.

Trả lời

10

Chạy ví dụ sau và bạn sẽ thấy lý do tại sao nó không hoạt động.

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> 

Mã-đằng sau:

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; 
     } 
    } 
} 

Như bạn có thể nhìn thấy khi chạy, chọn "mới" liên tiếp gây ra một giá trị trọng điểm được thiết lập như là mục đã chọn trong DataGrid. Tuy nhiên, WPF không thể chuyển đổi mục được gửi tới một số Person, do đó, ràng buộc SelectedItem không chuyển đổi được.

Để khắc phục điều này, bạn có thể đặt bộ chuyển đổi trên liên kết của mình để phát hiện con dấu và trả lại null khi được phát hiện. Dưới đây là một chuyển đổi mà không vậy:

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; 
     } 
    } 
} 

Như bạn thấy, nó là một sự cần thiết không may để kiểm tra so với giá trị ToString() của sentinel, bởi vì nó là một loại nội bộ. Bạn có thể cách khác (hoặc ngoài ra) kiểm tra xem GetType().NameNamedObject.

+2

5 năm sau, nhưng cũng có thể đặt nó ở đây: Bạn có thể so sánh nó với CollectionView.NewItemPlaceholder, đó là điều tương tự bạn đang làm, mà không cần phải ghi chuỗi "{NewItemPlaceholder}" trên mã của bạn. –

0

Khó nói nhưng không có mã, nhưng tôi sẽ xem xét những điều sau đây.

Đảm bảo rằng bất cứ khi nào một mục bị xóa và nó cũng là mục đã chọn, hãy đặt mục đã chọn được gắn với thuộc tính trong ViewModel của bạn thành rỗng. Bạn sẽ cần phải đảm bảo rằng SelectedItem của bạn bị ràng buộc vào tài sản không bị ràng buộc trên đường.

0

Có vẻ như bạn quên đặt Chế độ ràng buộc và mặc định được đặt thành OneWay. Điều này có nghĩa là bất kỳ thay đổi nào được thực hiện trong Chế độ xem của bạn sẽ không truyền lại cho mô hình chế độ xem của bạn.

Và luôn đảm bảo bạn có datacontext phù hợp.

Hy vọng điều đó sẽ hữu ích.

Các vấn đề liên quan