Habib Gherairi
Habib Gherairi

Reputation: 291

WPF Autocompletebox MVVM how to get selectedItem from another control?

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 .

enter image description here

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

Answers (1)

Habib Gherairi
Habib Gherairi

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

Related Questions