2013-08-02 63 views
10

Tôi đang sử dụng mẫu MVVM và tôi đã tạo một ràng buộc trong XAML cho SelectedItem của một DataGrid. Tôi lập trình thiết lập SelectedItem, tuy nhiên khi tôi làm như vậy DataGrid không di chuyển đến vùng chọn. Có cách nào tôi có thể đạt được điều này mà không hoàn toàn phá vỡ các mô hình MVVM?ScrollIntoView cho WPF DataGrid (MVVM)

Tôi tìm thấy giải pháp sau đây nhưng tôi nhận được một lỗi khi tôi cố gắng thực hiện các lớp Behavior, mặc dù tôi đã cài đặt Blend SDK: http://www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when-using-MVVM

+0

Bạn gặp phải lỗi gì khi cố triển khai 'Hành vi'? – Gjeltema

+0

@Gjeltema 'Không thể tìm thấy loại tên hoặc không gian tên 'Hành vi' (bạn thiếu một chỉ thị sử dụng hoặc tham chiếu assembly?)' – Andy

+0

Bạn có tham chiếu đến System.Windows.Interactivity.dll trong dự án của bạn không? – Gjeltema

Trả lời

29

này nên làm việc. Ý tưởng là bạn có thuộc tính đính kèm này mà bạn sẽ đính kèm vào DataGrid. Trong xaml nơi bạn đính kèm nó, bạn sẽ liên kết nó với một thuộc tính trên ViewModel của bạn. Bất cứ khi nào bạn muốn gán một giá trị theo cách lập trình cho SelectedItem, bạn cũng đặt giá trị cho thuộc tính này, thuộc tính được đính kèm sẽ được liên kết.

Tôi đã tạo loại thuộc tính đính kèm là bất kể loại SelectedItem là gì, nhưng thành thật không quan trọng loại nào miễn là bạn đặt nó thành thứ gì đó khác so với trước đây. Thuộc tính đính kèm này chỉ được sử dụng như một phương tiện để thực hiện một số mã trên điều khiển xem (trong trường hợp này là DataGrid) theo kiểu MVVM thân thiện.

Vì vậy, những gì đã nói, đây là mã cho tài sản gắn liền:

namespace MyAttachedProperties 
{ 
    public class SelectingItemAttachedProperty 
    { 
     public static readonly DependencyProperty SelectingItemProperty = DependencyProperty.RegisterAttached(
      "SelectingItem", 
      typeof(MySelectionType), 
      typeof(SelectingItemAttachedProperty), 
      new PropertyMetadata(default(MySelectionType), OnSelectingItemChanged)); 

     public static MySelectionType GetSelectingItem(DependencyObject target) 
     { 
      return (MySelectionType)target.GetValue(SelectingItemProperty); 
     } 

     public static void SetSelectingItem(DependencyObject target, MySelectionType value) 
     { 
      target.SetValue(SelectingItemProperty, value); 
     } 

     static void OnSelectingItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
     { 
      var grid = sender as DataGrid; 
      if (grid == null || grid.SelectedItem == null) 
       return; 

      // Works with .Net 4.5 
      grid.Dispatcher.InvokeAsync(() => 
      { 
       grid.UpdateLayout(); 
       grid.ScrollIntoView(grid.SelectedItem, null); 
      }); 

      // Works with .Net 4.0 
      grid.Dispatcher.BeginInvoke((Action)(() => 
      { 
       grid.UpdateLayout(); 
       grid.ScrollIntoView(grid.SelectedItem, null); 
      })); 
     } 
    } 
} 

Và đây là đoạn mã XAML:

<Window ... 
     xmlns:attachedProperties="clr-namespace:MyAttachedProperties"> 
    ... 
     <DataGrid 
      attachedProperties:SelectingItemAttachedProperty.SelectingItem="{Binding MyViewModel.SelectingItem}"> 
      ... 
     </DataGrid> 
    </Grid> 
+0

+1 Cảm ơn bạn rất nhiều vì câu trả lời của bạn. Tuy nhiên tôi nhận được lỗi sau: 'System.Windows.Threading.Dispatcher 'không chứa định nghĩa cho' InvokeAsync 'và không có phương thức mở rộng' InvokeAsync 'chấp nhận đối số đầu tiên của loại' System.Windows.Threading.Dispatcher 'có thể được tìm thấy (bạn đang thiếu một chỉ thị bằng cách sử dụng hoặc một tham chiếu lắp ráp?) '. Bất kỳ ý tưởng tại sao? Tôi đã thay đổi 'MySelectionType' – Andy

+0

@Andy Apologies, tôi vẫn đang làm việc .Net 4.5. Tôi sẽ cập nhật câu trả lời của tôi để phản ánh .Net 4.0. – Gjeltema

+0

oh ok haha, được rồi! Nó hoạt động hoàn hảo ngay bây giờ - một DLL ít hơn! Chúc tôi có thể upvote câu trả lời của bạn một lần nữa! – Andy

6

Tôi mới vào MVVM. Tôi hiểu ý tưởng của MVVM và cố gắng thực hiện mọi thứ một cách chính xác. Tôi đã có một vấn đề tương tự như trên và tôi đã kết thúc với 1 dòng trong XAML và 1 dòng mã phía sau. Phần còn lại của mã nằm trong VM. tôi đã làm như sau trong XAML

<ListBox DockPanel.Dock="Top" 
    Name="Selection1List" 
    ItemsSource="{Binding SelectedList1ItemsSource}" 
    SelectedItem="{Binding SelectedList1Item}" 
    SelectedIndex="{Binding SelectedList1SelectedIndex}" 
    SelectionChanged="Selection1List_SelectionChanged"> 

Và điều này trong các mã sau:

private void Selection1List_SelectionChanged(object sender, SelectionChangedEventArgs e) { 
    Selection1List.ScrollIntoView(Selection1List.SelectedItem); 
} 

và điều này hoạt động tốt.

Tôi biết một số người không muốn ngay cả một dòng mã trong mã phía sau cửa sổ. Nhưng tôi nghĩ rằng 1 dòng này là chỉ cho xem. Nó không liên quan gì đến dữ liệu hoặc với logic của dữ liệu. Vì vậy, tôi nghĩ rằng điều này không vi phạm nguyên tắc MVVM - và dễ thực hiện hơn rất nhiều.

Mọi nhận xét đều được chào đón.