【发布时间】: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