WPF Autocomplete dans une datagrid comment récupérer la sélection en cours
Je suis en train de tester le contrôle AutocompleteBox dans une datagrid et j'ai rencontré deux petits problèmes :
1°) Comment entrer directement en mode edititon lors du focus de la cellule contenant l'autocomplete ?
2°) Comment récupérer la sélection de l'autocomplete pour pouvoir mettre à jour toute la ligne
J'utilise MVVM Light
voici mon code :
Code:
1 2 3 4 5 6 7 8 9 10 11
|
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyViewModel mv = (MyViewModel) FindResource("MyViewModel");
this.DataContext = mv;
}
} |
et la classe Person
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
namespace WpfPlayingWithDatagrid
{
public class Person
{
int code;
public int Code
{
get { return code; }
set { code = value; }
}
string nom;
public string Nom
{
get { return nom; }
set { nom = value; }
}
string adresse;
public string Adresse
{
get { return adresse; }
set { adresse = value; }
}
public Person(int c, string n, string a)
{
Code = c;
Nom = n;
Adresse = a;
}
}
} |
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
public class MyViewModel : ObservableObject
{
ObservableCollection<Person> _names = null;
RelayCommand _loadClients;
RelayCommand _showSelectedPerson;
Person _selectedPerson;
public Person SelectedPerson
{
get { return _selectedPerson; }
set { _selectedPerson = value; }
}
public ObservableCollection<Person> Names
{
get { return _names; }
set { _names = value;
RaisePropertyChanged("Names");
}
}
public RelayCommand LoadClientCommand
{
get
{
if (_loadClients == null)
_loadClients = new RelayCommand(LoadCommandExecute);
return _loadClients;
}
}
private void LoadCommandExecute()
{
LoadClients();
}
public void LoadClients()
{
List<Person> ll = new List<Person>(5);
ll.Add(new Person(1,"ETS CUSTOMER1","Addresse1"));
ll.Add(new Person(2,"COMPX CUSTOMER2","Addresse 2"));
ll.Add(new Person(3,"ENTREPRISE3","Adresse3"));
ll.Add(new Person(4,"SOCIETE X4HERTZ","Addresse4"));
ll.Add(new Person(5,"CARCOMP","Addresse5"));
Names = new ObservableCollection<Person>(ll);
}
public RelayCommand ShowSelectedPersonCommand
{
get
{
if (_showSelectedPerson == null)
_showSelectedPerson = new RelayCommand(ShowSelectedPersonCommandExecute);
return _showSelectedPerson;
}
}
private void ShowSelectedPersonCommandExecute()
{
if (SelectedPerson != null)
MessageBox.Show(SelectedPerson.Nom);
else
MessageBox.Show("No selection.");
}
public RelayCommand<Person> SelectionChangedCommand
{
get
{
if (_selectchangedcommand == null)
_selectchangedcommand = new RelayCommand<Person>(SelectionChangedCommandExecute);
return _selectchangedcommand;
}
}
private void SelectionChangedCommandExecute(Person SelectedPerson)
{
MessageBox.Show(SelectedPerson.ToString());
}
}
} |
et le XAML
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
<Window x:Class="WpfPlayingWithDatagrid.MainWindow"
x:Name="wnd"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:gs="http://www.galasoft.ch/mvvmlight"
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
xmlns:local="clr-namespace:WpfPlayingWithDatagrid"
Title="MainWindow" >
<Window.Resources>
<local:MyViewModel x:Key="MyViewModel"/>
<Style x:Key="acbStyle" TargetType="controls:AutoCompleteBox">
<Setter Property="FilterMode" Value="Contains"/>
<Setter Property="IsTextCompletionEnabled" Value="True"/>
</Style>
<DataTemplate x:Key="AutoCompleteBoxItemTemplate">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Code}" Width="20" />
<Label Content="{Binding Nom}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<controls:AutoCompleteBox x:Name="acb1"
Grid.Column="0"
Grid.Row="0"
Margin="10"
ItemsSource="{Binding Names}"
ValueMemberBinding="{Binding Path=Nom}"
SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"
Style="{StaticResource acbStyle}"
ItemTemplate="{StaticResource AutoCompleteBoxItemTemplate}">
</controls:AutoCompleteBox>
<Button Grid.Column="2" Content="Show Selection" Command="{Binding ShowSelectedPersonCommand}" Margin="10"/>
<Button Grid.Column="1" Content="Load Customers" Command="{Binding LoadClientCommand}" Margin="10"/>
<DataGrid Grid.Row="1" Grid.ColumnSpan="3"
AutoGenerateColumns="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
RowHeight="30"
Grid.Column="0"
SelectionUnit="Cell"
ItemsSource="{Binding Names, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Grid.RowSpan="2"
>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Code, Mode=TwoWay, StringFormat=\{0:#\}}" Header="Code" />
<DataGridTemplateColumn Header="Name" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Nom}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<controls:AutoCompleteBox
x:Name="acb2"
Text="{Binding Nom}"
SelectedItem="{Binding Path=SelectedPerson}"
ItemsSource="{Binding Names,Source={StaticResource MyViewModel}}"
ValueMemberBinding="{Binding Nom}"
Style="{StaticResource acbStyle}"
ItemTemplate="{StaticResource AutoCompleteBoxItemTemplate}"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<gs:EventToCommand Command="{Binding SelectionChangedCommand}"
CommandParameter="{Binding SelectedItem,ElementName=this}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
</controls:AutoCompleteBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding Adresse, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Adresse" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window> |
Après fermeture de la fenêtre, Les erreurs suivantes apparaissent dans la fenêtre de débogage :
System.Windows.Data Error: 40 : BindingExpression path error: 'SelectedPerson' property not found on 'object' ''Person' (HashCode=5625554)'. BindingExpression:Path=SelectedPerson; DataItem='Person' (HashCode=5625554); target element is 'AutoCompleteBox' (Name='acb2'); target property is 'SelectedItem' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'SelectionChangedCommand' property not found on 'object' ''Person' (HashCode=5625554)'. BindingExpression:Path=SelectionChangedCommand; DataItem='Person' (HashCode=5625554); target element is 'EventToCommand' (HashCode=59400250); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=this'. BindingExpression:Path=SelectedItem; DataItem=null; target element is 'EventToCommand' (HashCode=59400250); target property is 'CommandParameter' (type 'Object')
Merci de votre aide
RE- WPF Autocomplete dans une datagrid comment récupérer la sélection en cours
Après quelques modifications, j'ai pu supprimer les messages d'erreurs ainsi que récupérer la sélection courante :
Voici le code de l'autocompletebox:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
<controls:AutoCompleteBox
x:Name="acb2"
Text="{Binding Nom}"
ItemsSource="{Binding Names,Source={StaticResource MyViewModel}}"
SelectedItem="{Binding Path=SelectedPerson, Source={StaticResource MyViewModel}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ValueMemberBinding="{Binding Nom}"
Style="{StaticResource acbStyle}"
ItemTemplate="{StaticResource AutoCompleteBoxItemTemplate}"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<gs:EventToCommand Command="{Binding SelectionChangedCommand, Source={StaticResource MyViewModel}}"
CommandParameter="{Binding Path=SelectedPerson, Source={StaticResource MyViewModel}}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
</controls:AutoCompleteBox> |
La propriété SelectedPerson devient :
Code:
1 2 3 4 5 6 7 8
|
public Person SelectedPerson
{
get { return _selectedPerson; }
set { _selectedPerson = value;
RaisePropertyChanged("SelectedPerson");
}
} |
et la méthode de l'affichage de la sélection courante dans le viewmodel doit être modifiée de la façon suivante :
Code:
1 2 3 4 5 6 7 8 9 10
|
private void SelectionChangedCommandExecute(Person SelectedPerson)
{
if (SelectedPerson != null)
MessageBox.Show(SelectedPerson.Code.ToString());
else
MessageBox.Show("Pas de sélection.");
} |
Il me reste maintenant le passage directement en mode édition dés le focus de la cellule contenant l'autocompletebox...