2014-09-23 149 views
1

我想在Windows 8.1应用程序中创建一个自动完成框。Listbox的SelectionChanged事件被多次触发

XAML代码:

<Grid Background="#CCFFFFFF" VerticalAlignment="Top" > 
     <TextBox x:Name="tb" IsTextPredictionEnabled="False" Margin="30" Height="50" PlaceholderText="Enter text" VerticalAlignment="Top" Background="Transparent" BorderBrush="#333333" Foreground="#333333" FontWeight="SemiBold" /> 
     <ListBox x:Name="lb" Background="Transparent" BorderBrush="#333333" MaxHeight="400" Visibility="Collapsed" Margin=" 30 80 30 30" VerticalAlignment="Top" > 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <Grid> 
         <Grid.ColumnDefinitions> 
          <ColumnDefinition Width="*" /> 
          <ColumnDefinition Width="*" /> 
          <ColumnDefinition Width="*" /> 
         </Grid.ColumnDefinitions> 
         <TextBlock Text="{Binding data}" Foreground="#333333"/> 
         <TextBlock Text="{Binding data1}" Grid.Column="1" Margin="10 0 10 0" Foreground="#333333"/> 
         <StackPanel Orientation="Horizontal" Grid.Column="2"> 
          <TextBlock Text="{Binding data2}" Margin="10 0 10 0" Foreground="#333333" /> 
          <TextBlock Text="{Binding data3}" Foreground="#333333" /> 
         </StackPanel> 
        </Grid> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 
    </Grid> 

事件处理程序:

 private async void tb_TextChanged(object sender, TextChangedEventArgs e) 
     { 
      lb.SelectionChanged -= lb_SelectionChanged; 
      if (tb.Text.Length < 1 || String.IsNullOrWhiteSpace(this.tb.Text)) 
      { 
       return; 
      } 
      try 
      { 
       var list = await Data.getData(); 
       lb.ItemsSource = list; 
       lb.Visibility = Windows.UI.Xaml.Visibility.Visible; 
       lb.SelectionChanged += lb_SelectionChanged; 
      } 
      catch (Exception ex) 
      { 
       System.Diagnostics.Debug.WriteLine(ex.Message.ToString()); 
      } 
     } 
     void lb_SelectionChanged(object sender, SelectionChangedEventArgs e) 
     { 
      tb.TextChanged -= tb_TextChanged; 
      if (lb.SelectedItem == null) 
      { 
       tb.TextChanged += tb_TextChanged; 
       lb.Visibility = Windows.UI.Xaml.Visibility.Collapsed; 
       return; 
      } 
      tb.Text = lb.SelectedItem.ToString(); 
      var item = (Data)lb.SelectedItem; 
      lb.Visibility = Windows.UI.Xaml.Visibility.Collapsed; 
      tb.TextChanged += tb_TextChanged; 
      System.Diagnostics.Debug.WriteLine("SelectionChanged Called\n"); 
     } 

的问题是,如果我键入textbox一个字符并从显示listbox选择一个项目,所述SelctionChanged事件引发一次。如果我键入两个字符,然后再次从显示框中选择一个项目,则会引发SelectionChanged事件两次,依此类推。

+0

为什么要在回调中删除并添加事件处理函数? – Dirk 2014-09-23 10:03:17

+0

因为我不想,直到自动完成列表框填充了最新的名单和副芦荟的文本框 – thunderbird 2014-09-23 10:07:07

+0

我通过删除列表框SelectionChanged事件'lb.SelectionChanged还挺固定问题的列表框可以进行选择 - = lb_SelectionChanged;前'仅仅指刚我添加了列表框选择更改事件'lb.SelectionChanged + = lb_SelectionChanged;'在'私人异步无效tb_TextChanged(对象发件人,TextChangedEventArgs e)'功能的try块中,但仍然不知道我以前做错了什么。 – thunderbird 2014-09-23 10:08:54

回答

1

问题是您的去除/与async方法中添加的事件处理程序的代码的组合。

想象一下以下情况:从lb.SelectionChangedtb_TextChanged被调用时,删除事件处理程序:

  • 用户输入的字符在文本框中。然后调用Data.GetData并在计划延续后立即返回。
  • 用户输入文本框在另一个字符:tb_TextChanged被调用时,从lb.SelectionChanged去除的事件处理程序。然后调用Data.GetData并在计划延续后立即返回。
  • 从所述第一呼叫到Data.GetData结果是可用的,继续执行lb_SelectionChanged添加了所述lb.SelectionChanged事件。
  • 从第二个呼叫至Data.GetData结果是可用的,继续执行lb_SelectionChanged添加了所述lb.SelectionChanged事件。

现在SelectionChanged有两个元素,你的lb_SelectionChanged将被调用两次。

我不会用一个方案一样,在那里你添加/删除在飞行的时间事件。一个简单的布尔变量应该更好。