1

I managed to build a custom listbox where each item is loaded from a database showing in a stackpanel the name and the lastname. After these 2 textboxes there should be a button, which is correctly binded to an ICommand of the ViewModel. The button correctly calls the right method, but it doesn't delete the selectedPerson because that object is null.

This is the WPF of the listbox

<Style x:Key="CustomHorizontalListbox" TargetType="{x:Type ListBox}">
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <Border BorderBrush="Black" BorderThickness="2">
                <StackPanel Orientation="Horizontal" Width="200" Margin="0,0,0,0">
                    <TextBox Text="{Binding FirstName}" Width="60" BorderThickness="0" Margin="0" IsReadOnly="True"></TextBox>
                    <TextBox Text="{Binding LastName}" Width="100" BorderThickness="0" Margin="0" IsReadOnly="True"></TextBox>
                    <Button Width="20" Height="20" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.OnDeletePatient}" CommandParameter="{Binding}"></Button>
                </StackPanel>
                </Border>
            </DataTemplate>
        </Setter.Value>                
    </Setter>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <WrapPanel></WrapPanel>
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>

This is the relative method on the ViewModel

private void DeletePatient()
    {
        patientsManager.DeletePatient(SelectedPatient);
        ListOfPatients = new ObservableCollection<RealPatient>(patientsManager.GetAllRealPatients());
        SelectedPatient = null;
    }

And this is how the custom listbox is included in the View

<ListBox Grid.Row="2" Grid.Column="3" Style="{StaticResource CustomHorizontalListbox}" ItemsSource="{Binding ListOfPatients}" SelectedItem="{Binding SelectedPatient}">

    </ListBox>

So the problem is that the breakpoint at the DeleteMethod shows the SelectedPatient = null..

What do i miss?... Even when i click on the list item and not on the single button the SelectedPatient doesn't change

thanks

Ivan_nn2
  • 469
  • 7
  • 20

1 Answers1

0

Here my full sample application that works:

    <Window.Resources>
    <Style x:Key="CustomHorizontalListbox" TargetType="{x:Type ListBox}">
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border BorderBrush="Black" BorderThickness="2">
                        <StackPanel Orientation="Horizontal" Width="200" Margin="0,0,0,0">
                            <TextBox Text="{Binding FirstName}" Width="60" BorderThickness="0" Margin="0" IsReadOnly="True"></TextBox>
                            <TextBox Text="{Binding LastName}" Width="100" BorderThickness="0" Margin="0" IsReadOnly="True"></TextBox>
                            <Button Width="20" Height="20" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.OnDeletePatient}" CommandParameter="{Binding}"></Button>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <WrapPanel></WrapPanel>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="{x:Type ListBoxItem}">
        <Style.Resources>
            <Storyboard x:Key="OnGotKeyboardFocus1">
                <BooleanAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="{x:Null}" Storyboard.TargetProperty="(Selector.IsSelected)">
                    <DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True"/>
                </BooleanAnimationUsingKeyFrames>
            </Storyboard>
        </Style.Resources>
        <Style.Triggers>
            <EventTrigger RoutedEvent="Keyboard.GotKeyboardFocus">
                <BeginStoryboard Storyboard="{StaticResource OnGotKeyboardFocus1}"/>
            </EventTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Window.DataContext>
    <Regions:ViewModel/>
</Window.DataContext>
<Grid>
    <ListBox Style="{StaticResource CustomHorizontalListbox}" ItemsSource="{Binding ListOfPatients}" SelectedItem="{Binding SelectedPatient}" >

    </ListBox>
</Grid>

Here the definition of my SelectedPatient property in the ViewModel:

    private Patient _SelectedPatient;
    public Patient SelectedPatient
    {
        get { return _SelectedPatient; }
        set
        {
            _SelectedPatient = value;
            NotifyPropertyChanged(m => m.SelectedPatient);
        }
    }

That will set your selected Item whenever you click in any place of your ListBox item row.

I wish I had a deeper explanation on why this works, but I found it in the MSDN forum: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/1642c5f9-e731-4a3d-9eed-0f574d90d925 I used that fix for the app I'm working with.

Adolfo Perez
  • 2,834
  • 4
  • 41
  • 61
  • It works well, but please if someone has the explanation of this can write it somewhere or gives some useful link?... – Ivan_nn2 Apr 02 '13 at 14:26
  • It is a funky way of setting properties based on event triggers. Here is how I understand it, when a keyboard focus event is detected for this ListBoxItem (`GotKeyboardFocus`) then start an animation that will set your `TargetProperty=Selector.IsSelected` to true when it is done. Similar post: http://stackoverflow.com/questions/942548/setting-a-property-with-an-eventtrigger – Adolfo Perez Apr 02 '13 at 14:33