ListBox SelectionChanged only once?

528 views Asked by At

I have a ListBox which I add items to. Each time i select an item which is an object of a Person this person properties should be showed in textboxes. This person have person properties like age, name, sex and so on.

my listbox selection changed event only triggers one time or on new added items. It doesn't trigger when i click and an that is not just added.

Mainwindow.xaml.cs

namespace GUI_WPF_Eksamen
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    Backlog bl = new Backlog();

    public MainWindow()
    {

        InitializeComponent();

        DataContext = bl;
        this.PriorityComboBox.Items.Add("High");
        this.PriorityComboBox.Items.Add("Medium");
        this.PriorityComboBox.Items.Add("Low");
    }


    private void AddToProductBackLogBtn_Click(object sender, RoutedEventArgs e)
    {
        this.ProductBacklogList.Items.Add(bl);
        this.NameTextBox.Text = String.Empty;
    }


    private void ProductBacklogList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var item = this.ProductBacklogList.SelectedItem as Backlog;
        this.NameLabel.Content = item.NAME;
        this.DescriptionTextBlock.Text = item.DESCRIPTION;
        this.PriorityLabel.Content = item.PRIORITY;
        this.TimeLabel.Content = item.TIME;
    }

    private void AddToSprint_Click(object sender, RoutedEventArgs e)
    {
        var currentItem = this.ProductBacklogList.SelectedItem as Backlog;
        this.SprintBacklogList.Items.Add(currentItem);

    }
}
}

Mainwindow.xaml

<Window x:Class="GUI_WPF_Eksamen.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:GUI_WPF_Eksamen"
    Title="GUI WPF application" Height="800" Width="1200">
<Window.Background>
    <ImageBrush ImageSource="Images/chalkboard.jpg"/>
</Window.Background>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="69*"/>
        <RowDefinition Height="700*"/>
    </Grid.RowDefinitions>
    <Label x:Name="Title" Content="SCRUM-BOARD XXL" HorizontalAlignment="Center" HorizontalContentAlignment="Center" Margin="15,10,5,0" VerticalAlignment="Top" Width="1172" Height="56" FontSize="36" FontStyle="Italic" FontWeight="Bold" Foreground="White"/>

    <Grid HorizontalAlignment="Left" Height="680" Margin="15,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="354">
        <Grid.RowDefinitions>
            <RowDefinition Height="94*"/>
            <RowDefinition Height="44*"/>
            <RowDefinition Height="131*"/>
            <RowDefinition Height="53*"/>
            <RowDefinition Height="40*"/>
            <RowDefinition Height="46*"/>
            <RowDefinition Height="272*"/>
        </Grid.RowDefinitions>
        <Label Content="Navn" HorizontalAlignment="Left" Margin="0,44,0,0" VerticalAlignment="Top" Width="77" FontSize="16" Foreground="White"/>
        <Label Content="Beskrivelse&#xA;" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" Foreground="White" FontSize="16" Height="31" Grid.Row="1"/>
        <Label Content="Prioritet" HorizontalAlignment="Left" Margin="0,7,0,0" VerticalAlignment="Top" Width="67" FontSize="16" Foreground="White" Grid.Row="3"/>
        <Label Content="Estimeret tidsforbrug" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" Foreground="White" FontSize="16" Grid.Row="4" Grid.RowSpan="2"/>
        <TextBox x:Name="NameTextBox" HorizontalAlignment="Left" Height="23" Margin="51,52,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="303" Opacity="0.5" Text="{Binding Path=NAME}"/>
        <ComboBox x:Name="PriorityComboBox" HorizontalAlignment="Left" Margin="73,12,0,0" VerticalAlignment="Top" Width="152" RenderTransformOrigin="0.5,0.5" Opacity="0.5" Grid.Row="3" SelectedItem="{Binding Path=PRIORITY}">
            <ComboBox.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform/>
                    <RotateTransform Angle="0.036"/>
                    <TranslateTransform/>
                </TransformGroup>
            </ComboBox.RenderTransform>
        </ComboBox>
        <TextBox x:Name="TimeTextBox" HorizontalAlignment="Left" Height="23" Margin="0,6,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="204" Opacity="0.5" Grid.Row="5" Text="{Binding Path=TIME}"/>
        <Label Content="time(r)" HorizontalAlignment="Left" Margin="209,38,0,0" VerticalAlignment="Top" Foreground="White" FontSize="16" Width="57" Grid.Row="4" Grid.RowSpan="2"/>
        <TextBox x:Name="DescriptionTextBox" HorizontalAlignment="Left" Height="111" Margin="0,10,0,0" Grid.Row="2" TextWrapping="Wrap" VerticalAlignment="Top" Width="354" Opacity="0.5" Text="{Binding Path=DESCRIPTION}"/>
        <Button x:Name="AddToProductBackLogBtn" Content="Add Backlog item" HorizontalAlignment="Left" Grid.Row="6" VerticalAlignment="Top" Width="200" Height="27" Margin="66,0,0,0" Background="White" Opacity="0.7" Click="AddToProductBackLogBtn_Click"/>

    </Grid>

    <Grid HorizontalAlignment="Left" Height="680" Margin="374,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="808" RenderTransformOrigin="0.459,0.431">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="79*"/>
            <ColumnDefinition Width="47*"/>
            <ColumnDefinition Width="76*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="209*"/>
            <RowDefinition Height="131*"/>
        </Grid.RowDefinitions>
        <Label Content="Navn" HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="1" VerticalAlignment="Top" FontSize="16" Foreground="White" Height="31" Width="47"/>
        <Label Content="Beskrivelse" HorizontalAlignment="Left" Margin="10,55,0,0" Grid.Row="1" VerticalAlignment="Top" Foreground="White" FontSize="16" Height="31" Width="87"/>
        <Label Content="Prioritet&#xD;&#xA;" HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="1" VerticalAlignment="Top" Foreground="White" FontSize="16" Height="32" Grid.Column="1" Width="66"/>
        <Label Content="Estimeret tidsforbrug" Grid.Column="1" HorizontalAlignment="Left" Margin="10,55,0,0" Grid.Row="1" VerticalAlignment="Top" Foreground="White" FontSize="16" Height="31" Width="159"/>
        <Label x:Name="PriorityLabel" Content="" Grid.Column="1" HorizontalAlignment="Left" Margin="90,10,0,0" Grid.Row="1" VerticalAlignment="Top" FontSize="16" Foreground="White" Width="79" Height="31"/>
        <Label x:Name="TimeLabel" Grid.Column="2" HorizontalAlignment="Left" Margin="10,55,0,0" Grid.Row="1" VerticalAlignment="Top" Foreground="White" FontSize="16" Width="208" Height="31"/>
        <ListBox x:Name="ProductBacklogList" HorizontalAlignment="Left" Height="353" Margin="10,55,0,0" VerticalAlignment="Top" Width="292" DisplayMemberPath="NAME" Opacity="0.505" SelectionChanged="ProductBacklogList_SelectionChanged" RenderTransformOrigin="0.5,0.5">
            <ListBox.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform AngleY="-0.195"/>
                    <RotateTransform/>
                    <TranslateTransform Y="-0.497"/>
                </TransformGroup>
            </ListBox.RenderTransform>
        </ListBox>
        <ListBox x:Name="SprintBacklogList" HorizontalAlignment="Left" Height="353" Margin="10,55,0,0" VerticalAlignment="Top" Width="284" DisplayMemberPath="NAME" Grid.Column="2" Opacity="0.5"/>
        <Label x:Name="NameLabel" HorizontalAlignment="Left" Margin="62,14,0,0" Grid.Row="1" VerticalAlignment="Top" Width="244" Height="27" Content="{Binding Path=NAME}" Foreground="White"/>
        <Button x:Name="AddToSprint" Content="Add &gt;&gt;" Grid.Column="1" HorizontalAlignment="Left" Margin="54,201,0,0" VerticalAlignment="Top" Width="75" Height="20" Opacity="0.7" Click="AddToSprint_Click"/>
        <TextBlock x:Name="DescriptionTextBlock" HorizontalAlignment="Left" Margin="10,86,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Height="166" Width="296" Foreground="White"/>
    </Grid>
</Grid>

1

There are 1 answers

0
Olaru Mircea On

That way of selection changed can be accomplished easily:

Have a look here:

<Window x:Class="ListBoxSelection.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<DockPanel>
    <ListBox ItemsSource="{Binding persons}" IsSynchronizedWithCurrentItem="True" DockPanel.Dock="Top">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Name}" Margin="5,0"/>
                    <TextBlock Text="{Binding Age, StringFormat=is {0} years old}" Margin="5,0"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <StackPanel Orientation="Horizontal" DataContext="{Binding persons}" DockPanel.Dock="Top">
        <TextBlock Text="You have selected: " FontWeight="SemiBold"/>
        <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" 
                 Margin="5,0" 
                 FontWeight="SemiBold" 
                 VerticalAlignment="Top"
                 HorizontalAlignment="Center"/>
        <TextBox Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}"
                 Margin="5,0"
                 FontWeight="SemiBold" 
                 VerticalAlignment="Top" 
                 HorizontalAlignment="Left"/>
    </StackPanel> 
    <Button Content="Add Item" DockPanel.Dock="Top" Width="60" VerticalAlignment="Top" Margin="20" Click="btnAddItem_Click"/>
</DockPanel>

Note this down: IsSynchronizedWithCurrentItem="True"

From MSDN:

Gets or sets a value that indicates whether a Selector should keep the SelectedItem synchronized with the current item in the Items property.

What's the next step? Display the selected item:

<StackPanel DataContext="{Binding persons}"/>

StackPanel is not an ItemsControl, it will not try to display all the items in persons but instead it will look for the selected one.

The ICollectionView interface contains a member called CurrentItem. What the IsSynchronizedWithCurrentItem does is: whenever an item is clicked on the ItemsControl, it sets the CurrentItem for the collection view. The ICollectionView also has two events: CurrentItemChanging and CurrentItemChanged. When the IsSynchronizedWithCurrentItem property is set, the ItemsControl will update the SelectedItem based on what the ICollectionView's CurrentItem is.

Further more, using UpdateSourceTrigger=PropertyChanged you will be able to update you selected item and this will be immediately displayed in the ListBox.

OK, that's about, here is the rest of the code:

public class Person : INotifyPropertyChanged
{
    private string _Name;

    public string Name
    {
        get { return _Name; }
        set
        {
            _Name = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Name"));
        }
    }

    private int _Age;

    public int Age
    {
        get { return _Age; }
        set
        {
            _Age = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Age"));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

And the codebehind:

public partial class MainWindow : Window
{

    public ObservableCollection<Person> persons { get; set; }

    public Person SelectedPerson
    {
        get { return (Person)GetValue(SelectedPersonProperty); }
        set { SetValue(SelectedPersonProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SelectedPerson.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectedPersonProperty =
        DependencyProperty.Register("SelectedPerson", typeof(Person), typeof(MainWindow), new PropertyMetadata(null));

    public MainWindow()
    {
        InitializeComponent();
        persons = new ObservableCollection<Person>();
        persons.Add(new Person() { Name = "Name1", Age = 20 });
        persons.Add(new Person() { Name = "Name2", Age = 25 });
        persons.Add(new Person() { Name = "Name3", Age = 30 });
        this.DataContext = this;
    }

    private void btnAddItem_Click(object sender, RoutedEventArgs e)
    {
        persons.Add(new Person() { Name = "NameAdded", Age = 50 });
    }
}

As you see, your SelectionChanged handler is not needed anymore.

You may be asking, what is that SelectedPerson in the code behind:

Add this binding on the ListBox:

SelectedItem="{Binding SelectedPerson}"

And in that AddToSprint_Click use the SelectedPerson to get the Person instead of directly accessing the ListBox.