Reputation: 291
I try to develop a WPF user control (image below) that allows me to search customer by name or Number. To achieve this, I use MVVM Approach (MVVM Light).
How can i achieve the following goals at the same time :
1°) If I know the number I can enter it in the textbox and the name will automatically appear in the AutoCompleteBox
2°) If the customer number is unknown ,i use autocompletebox to search by name, then the Textbox must contain the number of selected customer .
The problem is : If i bind the textbox to the Autocompletebox selectedItem, second goal is achieved but not the first. When i press Enter key in the textbox, even when it contains valid code, I have always message "Customer not found." and the customer code is empty as if it is not bound to AutocompleteBox SelectedItem.
Below code :
//snipped from user control
<TextBox Text="{Binding ElementName=custName, Path=SelectedItem.CodeClient, UpdateSourceTrigger=PropertyChanged}" Width="80" Margin="8,8,0,8">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewKeyDown">
<gs:EventToCommand PassEventArgsToCommand="True"
Command="{Binding GetClientCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<Button Content="..." Margin="0,8,2,8" Width="20" Command="{Binding SearchCommand}"/>
<Label Content="Name" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5,5,0,5"/>
<controls:AutoCompleteBox x:Name="custName"
ItemsSource="{Binding ListClients}"
MinimumPrefixLength="3"
MinimumPopulateDelay="200"
ValueMemberBinding="{Binding Path=NomClient, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Text="{Binding Path=ClientName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
SelectedItem="{Binding ElementName=this, Path=CodeClient, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
FilterMode="Contains"
IsTextCompletionEnabled="True"
Width="400"
Margin="2,8,5,8"
>
<controls:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="Auto">
<TextBlock Text="{Binding Path=CodeClient, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="5" />
<TextBlock Text="{Binding Path=NomClient, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="5"/>
</StackPanel>
</DataTemplate>
</controls:AutoCompleteBox.ItemTemplate>
</controls:AutoCompleteBox>
</StackPanel>
//light class for customer contains only code and name for use in autocompletebox
public class ClientReduit : ObservableObject
{
string _codeclient;
public string CodeClient
{
get { return _codeclient; }
set { _codeclient = value;
RaisePropertyChanged("CodeClient");
}
}
string _nomclient;
public string NomClient
{
get { return _nomclient; }
set { _nomclient = value;
RaisePropertyChanged("NomClient");
}
}
long? _clientid;
public long? Clientid
{
get { return _clientid; }
set { _clientid = value;
}
}
}
//-------ViewModel de UserControl CustomerSearch
public class ViewModelRechercheClient : ObservableObject
{
Client _client;
string _codeClient;
string _nomClient;
bool _clientFound = false;
public bool ClientFound
{
get { return _clientFound; }
set { _clientFound = value;}
}
ObservableCollection<ClientReduit> _listClients;
public ObservableCollection<ClientReduit> ListClients
{
get
{
if (_listClients == null)
_listClients = new ObservableCollection<ClientReduit>();
return _listClients;
}
set
{
_listClients = value;
RaisePropertyChanged("ListClients");
}
}
public Client CurrentClient
{
get { return _client; }
set { _client = value; }
}
public string ClientName
{
get { return _nomClient; }
set { _nomClient = value;
RaisePropertyChanged("ClientName");
}
}
public string ClientCode
{
get { return _codeClient; }
set { _codeClient = value;
RaisePropertyChanged("ClientCode");
}
}
//Constructor
public ViewModelRechercheClient()
{
//Load customers
ListClients = new ObservableCollection<ClientReduit>((from c in (((App)Application.Current).GetListClient())
select new ClientReduit
{
CodeClient = c.r01_codcli,
NomClient = c.r01_nomcli.Trim(),
Clientid = c.CLIENTID
}).ToList());
}
//Command for TextBox PreviewkeyDown -> Key.Enter -->
ICommand _getClient;
//---------------------------------------------------------------------------------
//Commande de recherche client lors de l'entrée d'un code client et de l'appui sur
//la touche entrée
//---------------------------------------------------------------------------------
public ICommand GetClientCommand
{
get
{
if (_getClient == null)
_getClient = new RelayCommand<KeyEventArgs>(GetClientCommandExecute);
return _getClient;
}
}
private void GetClientCommandExecute(KeyEventArgs e)
{
bool processIt = false;
ClientFound = false;
if (e != null && e.Key == Key.Enter)
processIt = true;
if (e == null || processIt == true)
{
ILogger _currentLog = ((App)Application.Current).GetCurrentLogger();
using (UnitOfWork cx = new UnitOfWork(_currentLog))
{
ClientRepository _clientRepository = new ClientRepository(cx, _currentLog);
IClientManagementService cms = new ClientManagementService(_currentLog, _clientRepository);
CurrentClient = cms.FindById(ClientCode);
if (CurrentClient != null)
{
ClientFound = true;
ClientCode = CurrentClient.r01_codcli;
ClientName = CurrentClient.r01_nomcli;
}
else
{
ClientFound = false;
Messenger.Default.Send(new APPX.Presentation.Messages.DialogMessage(ClientCode + " : Customer not found."));
}
}
}
}
I think the Question lies in how to get the Customer Number from AutoCompleteBox SelectedItem while respecting MVVM Approach ?
thank you in advance.
Upvotes: 0
Views: 2720
Reputation: 291
I found a solution, but I do not know if it is the best, but it works well for me : Simply, i add a command that handle SelectionChanged event. in this command i get selectedItem and i assign it to ClientCode (bound to textBox)
below the code of a usercontrol
<StackPanel Orientation="Horizontal">
<Label Content="Number" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5,5,0,5" />
<!-- <TextBox Text="{Binding ElementName=custName, Path=SelectedItem.CodeClient, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Width="80"
Margin="8,8,0,8">-->
<TextBox x:Name="custCode" Text="{Binding ClientCode, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="8,8,0,8" Width="80">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewKeyDown">
<gs:EventToCommand PassEventArgsToCommand="True"
Command="{Binding GetClientCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<Button Content="..." Margin="0,8,2,8" Width="20" Command="{Binding SearchCommand}"/>
<Label Content="Name" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5,5,0,5"/>
<controls:AutoCompleteBox x:Name="custName"
ItemsSource="{Binding ListClients}"
MinimumPrefixLength="3"
MinimumPopulateDelay="200"
ValueMemberBinding="{Binding Path=NomClient, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Text="{Binding Path=ClientName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
SelectedItem="{Binding ElementName=this, Path=CodeClient, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
FilterMode="Contains"
IsTextCompletionEnabled="True"
Width="400"
Margin="2,8,5,8"
SelectionChanged="custName_SelectionChanged"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<gs:EventToCommand PassEventArgsToCommand="True"
Command="{Binding SetCodeClientCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<controls:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="Auto">
<TextBlock Text="{Binding Path=CodeClient, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="5" />
<TextBlock Text="{Binding Path=NomClient, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="5"/>
</StackPanel>
</DataTemplate>
</controls:AutoCompleteBox.ItemTemplate>
</controls:AutoCompleteBox>
</StackPanel>
and the command is as follows :
public ICommand SetCodeClientCommand
{
get
{
if (_setCodeClient == null)
_setCodeClient = new RelayCommand<SelectionChangedEventArgs>(SetCodeClientCommandExecute);
return _setCodeClient;
}
}
private void SetCodeClientCommandExecute(SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
ClientCode = (((ClientReduit)e.AddedItems[0]).CodeClient);
ClientFound = true;
}
}
Upvotes: 1