2013-08-02 117 views
10

我正在使用MVVM模式,並且我在DataGrid的SelectedItem的XAML中創建了一個綁定。我編程設置SelectedItem,但是當我這樣做DataGrid不滾動到選擇。有沒有什麼辦法可以在不完全打破MVVM模式的情況下實現這一目標?ScrollIntoView WPF數據網格(MVVM)

我發現下面的解決辦法,但我得到一個錯誤,當我嘗試實施Behavior類,即使我已經安裝了混合SDK:http://www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when-using-MVVM

+0

嘗試實施「行爲」時會出現什麼錯誤? – Gjeltema

+0

@Gjeltema'無法找到類型或命名空間名'行爲'(您是否缺少使用指令或程序集引用?)' – Andy

+0

您是否在項目中引用了System.Windows.Interactivity.dll? – Gjeltema

回答

29

這應該工作。這個想法是你有這個附加的屬性,你將附加到DataGrid。在附加它的xaml中,您將它綁定到您的ViewModel上的一個屬性。無論何時您想以編程方式爲SelectedItem賦值,您還要爲此屬性設置一個值,該屬性將綁定到該屬性。

我已將附加屬性類型設置爲SelectedItem類型,但老實說,只要您將其設置爲與以前不同的類型,什麼類型都無關緊要。這個附加屬性只是作爲一種手段,以MVVM友好的方式在視圖控件上執行一些代碼(在本例中爲DataGrid)。

所以,這麼說,這裏的附加屬性代碼:

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

而這裏的XAML片段:

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

+1非常感謝您的回答。然而,我得到以下錯誤:'System.Windows.Threading.Dispatcher'不包含'InvokeAsync'的定義,並且沒有擴展方法'InvokeAsync'接受類型'System.Windows.Threading.Dispatcher'的第一個參數可以找到(你是否缺少using指令或程序集引用?)'。任何想法爲什麼?我已經改變了MySelectionType – Andy

+0

@Andy道歉,我仍然在.Net 4.5中工作。我會更新我的答案以反映.Net 4.0。 – Gjeltema

+0

哦好吧,哈哈,沒關係!它現在工作完美 - 少一個DLL!希望我能再次提出您的答案! – Andy

6

我是新來MVVM。我理解MVVM的想法並嘗試正確地實現一切。 我有一個類似的問題,以上,我結束了1行XAML和1行代碼後面。其餘的代碼在虛擬機中。 我沒有在XAML

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

這在後面的代碼:

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

,這工作得很好。

我知道有些人甚至不希望窗口後面的代碼中有一行代碼。但我認爲這1條線只是爲了這個觀點。它與數據或數據的邏輯無關。所以我認爲這不違反MVVM原則 - 而且更容易實現。

歡迎任何評論。