I'm using the MVVM pattern, and I've created a binding in XAML for the SelectedItem of a DataGrid. I programatically set the SelectedItem, however when I do so the DataGrid does not scroll to the selection. Is there any way I can achieve this without completely breaking the MVVM pattern?
I found the following solution but I get an error when I try to implement the Behavior
class, even though I've installed Blend SDK: http://www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when-using-MVVM
This should work. The idea is you have this attached property that you will attach to the DataGrid
. In the xaml where you attach it, you'll bind it to a property on your ViewModel
. Whenever you want to programmatically assign a value to the SelectedItem
, you also set a value to this property, which the attached property is bound to.
I've made the attached property type to be whatever the SelectedItem
type is, but honestly it doesn't matter what the type is as long as you set it to something different than what it was before. This attached property is just being used as a means to execute some code on the view control (in this case, a DataGrid
) in an MVVM friendly fashion.
So, that said, here's the code for the attached property:
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); })); } } }
And here's the xaml snippet:
<Window ... xmlns:attachedProperties="clr-namespace:MyAttachedProperties"> ... <DataGrid attachedProperties:SelectingItemAttachedProperty.SelectingItem="{Binding MyViewModel.SelectingItem}"> ... </DataGrid> </Grid>
I am new to MVVM. I understand the idea of MVVM and try to implement everything correctly. I had a similar problem to above and I ended up with 1 line in XAML and 1 line in code behind. The rest of the code is in the VM. I did the following in XAML
<ListBox DockPanel.Dock="Top" Name="Selection1List" ItemsSource="{Binding SelectedList1ItemsSource}" SelectedItem="{Binding SelectedList1Item}" SelectedIndex="{Binding SelectedList1SelectedIndex}" SelectionChanged="Selection1List_SelectionChanged">
And this in the code behind:
private void Selection1List_SelectionChanged(object sender, SelectionChangedEventArgs e) { Selection1List.ScrollIntoView(Selection1List.SelectedItem); }
and this works fine.
I know some people don't want even one line of code in the code behind the window. But I think this 1 line is just for the view. It has nothing to do with the data or with the logic of the data. So I would think this is no violation of the MVVM principle - and so much easier to implement.
Any comments are welcome.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With