Reputation: 561
I'm trying to make a DataGrid where the user can edit data and apply oder cancel changes afterwards.
Moreover one DataGridCell
has a TemplateSelector
to help the user to enter just the valid data. (DateTime, Boolean,...)
My Model has some properties. For my problem there are two relevant:
Model.Type
and Model.Value
In CodeBehind my properties have the type:
enum Type;
string Value;
When the user edits the Value
the TemplateSelector should get the right DataTemplate depending on Type
My XAML looks like this:
<DataGrid x:Name="datagrid"
ItemsSource="{Binding Variables}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AutoGenerateColumns="False"
IsSynchronizedWithCurrentItem="True">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="{StaticResource VariablesType}"
ItemsSource="{Binding Source={StaticResource VariableTypes}, Mode=OneWay}"
SelectedItemBinding="{Binding Type}"
Width="80"/>
<DataGridTemplateColumn Header="{StaticResource VariablesValue}" Width="2*">
<DataGridTemplateColumn.CellEditingTemplateSelector>
<TemplateSelector:TemplateSelector_Variables>
<!--Definitin of Templates,..-->
</TemplateSelector:TemplateSelector_Variables>
</DataGridTemplateColumn.CellEditingTemplateSelector>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Let's get to the TemplateSelector:
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item == null)
return base.SelectTemplate(item, container);
RaVariableType VariablenType = ((RaVariable)item).Type;
//SelectingLogic
//Here I would need the CURRENT type but it gives me the type of my Model
}
I have alread had a solution: If I use:
SelectedItemBinding="{Binding Type, UpdateSourceTrigger="PropertyChanged"}"
It works BUT I would like to handle an OK
or Cancel
of the User and this code changes my Model.
Another question: How do you handle such a decition. (How do you update the Model - code of the command)
Thank you!
Upvotes: 0
Views: 509
Reputation: 1
Are you using MVVM pattern. You need to handle it in View Model just bind button to the SelectedItem of the DataGrid and use it whenever the Command is invoked. Ideal way to do this kind of stuff is using commands (Basically MVVM pattern) you can create a command in your Data Object(ViewModel) and call Button.Command , So that there wont be any code behind like Button click.
Example is shown here
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Button
Command="{Binding Path=DataContext.OKCommand,
RelativeSource= {RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}}">
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
View model code
RelayCommand _okCommand;
public ICommand okCommand
{
get
{
if (_ok == null)
{
_ok= new RelayCommand(param => this.Show());
}
return _ok;
}
}
private void Show()
{
if (Parent != null)
{
// Handle ok logic Here
}
}
Are you using any patterns like Ninject, Unity etc and entity framework for handling your db layer code ?. Your viewmodel will contain properties and the column names of your grid should come from model property. Once the property value changes you need to write save logic probably using EF or linq to sql db code. Save logic will be handled by seperate class and if the user clicks a button your view model should call the interface method and do the save. Instance of your class which handles save logic will be supplied by Unity or Ninject (depending on your implementation). Your dependencies will be injected into your view models, and your view models would expose properties that are bound to by the view.
For passing the selected item from grid to model Create a Property in the ViewModel for saving the selected User: public User SelectedUser { get; set; }
Bind SelectedItem of the datagrid view to this Property: SelectedItem="{Binding SelectedUser}"
There are a few way to select items in the DataGrid. It just depends which one works best for your situation
First and most basic is SelectedIndex this will just select the Row at that index in the DataGrid
<DataGrid SelectedIndex="{Binding SelectedIndex}" />
private int _selectedIndex;
public int SelectedIndex
{
get { return _selectedIndex; }
set { _selectedIndex = value; NotifyPropertyChanged("SelectedIndex"); }
}
SelectedIndex = 2;
SelectedItem will select the row that matches the row you set
<DataGrid SelectedItem="{Binding SelectedRow}" />
private DataRow _selectedRow;
public DataRow SelectedRow
{
get { return _selectedRow; }
set { _selectedRow = value; NotifyPropertyChanged("SelectedRow");}
}
SelectedRow = items.First(x => x.whatever == something);
The most common one is SelectedValue with SelectedValuePath set, in this case you set the column you want to select with and then to can select the row by setting the corresponding value
<DataGrid SelectedValuePath="Size Quantity" SelectedValue="{Binding SelectionValue}"
private string _selectedValue
public string SelectionValue
{
get { return _selectedValue; }
set { _selectedValue = value; NotifyPropertyChanged("SelectionValue"); }
}
SelectionValue = "Blue";
XAML Example
<Window x:Class="WpfApplication21.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="202" Width="232" Name="UI">
<Grid DataContext="{Binding ElementName=UI}">
<DataGrid SelectedValuePath="Size Quantity"
SelectedValue="{Binding SelectionValue}"
SelectedIndex="{Binding SelectedIndex}"
ItemsSource="{Binding SizeQuantityTable}"
AutoGenerateColumns="True"
Margin="0,0,0,41" />
<StackPanel Orientation="Horizontal" Height="37" VerticalAlignment="Bottom" >
<Button Content="SelectedIndex" Height="26" Width="107" Click="Button_Click_1"/>
<Button Content="SelectedValue" Height="26" Width="107" Click="Button_Click_2"/>
</StackPanel>
</Grid>
</Window>
Upvotes: 1