thunderbird thunderbird - 3 months ago 18
C# Question

Listbox's SelectionChanged event getting fired multiple times

I am trying to make an auto-complete box in a Windows 8.1 app.

Xaml Code:

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


EventHandler:

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


The problem is if i type one character in the
textbox
and select an item from the displayed
listbox
, the
SelctionChanged
event is raised once. If i type two characters and then again select an item from the displayed box, the
SelectionChanged
event is thrown twice and so on.

Answer

The problem is your removing/add code of the event handlers in combination with an async method.

Imagine following situation:

  • User enters character in textbox: tb_TextChanged is called, removed event handler from lb.SelectionChanged. Then calls Data.GetData and returns immediately after scheduling a continuation.
  • User enters another character in textbox: tb_TextChanged is called, removed event handler from lb.SelectionChanged. Then calls Data.GetData and returns immediately after scheduling a continuation.
  • The result from the first call to Data.GetData is available, continuation is executed lb_SelectionChanged is added the the lb.SelectionChanged event.
  • The result from the second call to Data.GetData is available, continuation is executed lb_SelectionChanged is added the the lb.SelectionChanged event.

Now SelectionChanged has two elements and your lb_SelectionChanged will be called twice.

I would not use a scheme like that where you add/remove events on the fly all the time. A simple boolean variable should work much better.

Comments