Problem with DataGrid Rows in WPF
I have a datagrid where I have two buttons on each row - one for moving a row up and one for moving a row down.
Each button has a command for allowing the user to move the selected row in either direction. The problem that I am facing is that it not working. I think the problem that I may have is that the other controls (combo boxes) on the rows are bound to data sources through the MVVM model where I am manipulating the rows on the code behind of the XAML thinking this would be the logical place in which to do it.
The code I have for one of the buttons is below:
private void MoveRowDown(object sender, ExecutedRoutedEventArgs e)
{
int currentRowIndex = dg1.ItemContainerGenerator.IndexFromContainer(dg1.ItemContainerGenerator.ContainerFromItem(dg1.SelectedItem));
if (currentRowIndex >= 0)
{
this.GetRow(currentRowIndex + 1).IsSelected = true;
}
}
privat开发者_如何学运维e DataGridRow GetRow(int index)
{
DataGridRow row = (DataGridRow)dg1.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
dg1.UpdateLayout();
dg1.ScrollIntoView(selectedAttributes.Items[index]);
row = (DataGridRow)dg1.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
You have to manipulate the CollectionView
for the DataGrid. The CollectionView is responsible for how your data looks like basically. Here is a small example:
Let's assume you've bound your DataGrid
to an ObservableCollection<T>
named Items, and that T
has a property called Index on which is sorted.
Initialize the ICollectionView
in your ViewModel like this:
private ICollectionView cvs;
ctor(){
/*your default init stuff*/
/*....*/
cvs = CollectionViewSource.GetDefaultView(items);
view.SortDescriptions.Add(new SortDescription("Index",ListSortDirection.Ascending));
}
Now you can bind your button command to the Up command (also in your ViewModel):
private ICommand upCommand;
public ICommand Up
{
get { return upCommand ?? (upCommand = new RelayCommand(p => MoveUp())); }
}
private void MoveUp()
{
var current = (Item)view.CurrentItem;
var i = current.Index;
var prev = Items.Single(t => t.Index == (i - 1));
current.Index = i - 1;
prev.Index = i;
view.Refresh(); //you need to refresh the CollectionView to show the changes.
}
WARNING: you have to add checks to see if there is a previous item etc. Alternatively you can specify a CanExecute delegate which checks the Index of the item and enables/disables the button.
(RelayCommand
courtesy of Josh Smith/Karl Shifflett, can't find the correct link anymore)
Bind the command to you button like this (assuming your viewmodel is the DataContext of your window):
<DataGridTemplateColumn >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Up"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},
Path=DataContext.Up}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Hope this helps!
精彩评论