列表框的SelectionChanged事件多次被触发

时间:2014-09-23 09:35:50

标签: c# xaml listbox windows-store-apps

我正在尝试在Windows 8.1应用中制作一个自动完成的框。

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事件将被抛出两次,依此类推。

1 个答案:

答案 0 :(得分:1)

问题是您使用async方法删除/添加事件处理程序的代码。

想象一下以下情况:

  • 用户在文本框中输入字符:调用tb_TextChanged,从lb.SelectionChanged删除事件处理程序。然后调用Data.GetData并在安排延续后立即返回。
  • 用户在文本框中输入另一个字符:调用tb_TextChanged,从lb.SelectionChanged删除事件处理程序。然后调用Data.GetData并在安排延续后立即返回。
  • 第一次调用Data.GetData的结果可用,继续执行lb_SelectionChanged添加lb.SelectionChanged事件。
  • 第二次调用Data.GetData的结果可用,继续执行lb_SelectionChanged添加lb.SelectionChanged事件。

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

我不会使用像您一直在动态添加/删除事件的方案。一个简单的布尔变量应该可以更好地工作。