【问题标题】:WPF Autocompletebox MVVM how to get selectedItem from another control?WPF Autocompletebox MVVM 如何从另一个控件获取 selectedItem?
【发布时间】:2014-07-17 10:44:09
【问题描述】:

我尝试开发一个 WPF 用户控件(下图),它允许我按名称或编号搜索客户。为此,我使用了 MVVM 方法(MVVM Light)。

我怎样才能同时实现以下目标:

1°) 如果我知道数字,我可以在文本框中输入它,名称将自动出现在 AutoCompleteBox 中

2°) 如果客户编号未知,我使用自动完成框按名称搜索,那么文本框必须包含所选客户的编号。

问题是: 如果我将文本框绑定到 Autocompletebox selectedItem,则实现了第二个目标,但不是第一个目标。当我在文本框中按 Enter 键时,即使它包含有效代码,我也会始终显示“找不到客户”消息。并且客户代码是空的,好像它没有绑定到 AutocompleteBox SelectedItem。

以下代码:

//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."));
                }

            }
        }
    }

我认为问题在于如何在尊重 MVVM 方法的同时从 AutoCompleteBox SelectedItem 获取客户编号?

提前谢谢你。

【问题讨论】:

  • 两个TextBoxes?真的吗?为什么不能让用户在AutoCompleteTextBox 控件中输入名称或数字?这将大大简化情况并为用户提供更好的用户体验。
  • 如果用户知道客户编号,则将其输入文本框中,无需使用自动完成框。您提到 autocompletbox 可以同时绑定到名称或数字,如何?

标签: wpf autocomplete mvvm-light


【解决方案1】:

我找到了一个解决方案,但我不知道它是否是最好的,但它对我来说效果很好: 简单地说,我添加了一个处理 SelectionChanged 事件的命令。在此命令中,我得到 selectedItem 并将其分配给 ClientCode(绑定到 textBox)

在用户控件的代码下方

<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>

命令如下:

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;
        }

    }

【讨论】:

    猜你喜欢
    • 2012-06-19
    • 2011-11-01
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    • 2013-07-04
    • 2015-03-13
    • 2014-03-18
    • 2020-10-27
    相关资源
    最近更新 更多