StinkerPeter
StinkerPeter

Reputation: 165

MVVM Listbox DataTemplate SelectedItem

I am using a ListBox with a DataTemplate as shown below (xaml simplified and variable names changed).

<ListBox ItemsSource="{Binding Path=ObservCollectionItems}"
         SelectedItem="{Binding Path=SelectedItemVar, Mode=TwoWay}">
         <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding SomeVar}" />
                    <Border>
                        <StackPanel>
                            <Button Content="String1"
                                    Command="{Binding DataContext.Command1}
                                    RelativeSource={RelativeSource FindAncestor, ListBox, 1}}" />
                            <Button Content="String2" 
                                    Command="{Binding DataContext.Command2}
                                    RelativeSource={RelativeSource FindAncestor, ListBox, 1}}" />
                        </StackPanel>
                    </Border>
                </StackPanel>
            </DataTemplate>
         <ListBox.ItemTemplate>
 </ListBox>

I need the SelectedItemVar (dependency property) to update when I click on one of the buttons. SelectedItemVar is then used for the respective button's command. SelectedItemVar does update when I click on the TextBlock or the Border, but not when I click either button. I found a non-MVVM solution to this problem here. I do not want to add code in the file-behind to solve this, as they did in the link.

Is there a clean solution that can be done in XAML. Beyond the non-MVVM solutions, I have not found anyone with this problem. I would have thought this was fairly common.

Finally, I found this Command="{Binding DataContext.CommandName} RelativeSource={RelativeSource FindAncestor, ListBox, 1} for the Command binding. I do not fully understand what it is doing, but I do know that the command wasn't firing when I was binding directly to CommandName.

Upvotes: 2

Views: 3633

Answers (2)

Ankesh
Ankesh

Reputation: 4885

You are using MVVM .... so very simple solution to that is Passing the SelectedItem as Parameter to the command of Both button and then Setting the SelectedItem with the Value of the parameter.....

Code

public class YourViewmodel
{
     //Other Variables
     
     
     public YourViewModelCtor()
     {
        Command1= new RelayCommand(Command1Func);
     }
     
     Public SelectedVar
     {
             get {return value;}
             Set { selectedVar=value;
                       OnPropertyChanged("SelectedVar");
              }
     }

     //Other Properties


     void Command1Func(object obj)
     {
              SelectedVar= obj as <Your Desired Type>;

              //Do your thing with SelectedVar ... Do the same for Command2
     }
}

Changes required in Xaml

<StackPanel>
    <Button Command="{Binding DataContext.Command1}" CommandParameter="{Binding}"
            Content="String1" />
    <Button Command="{Binding DataContext.Command2}" CommandParameter="{Binding}"
            Content="String2" />
</StackPanel>

This will get you the current ListBox item ferom where you clicked the button....

This should do it...... :)

Upvotes: 5

Geoff Cox
Geoff Cox

Reputation: 6142

You need some code to handle the visual behavior you want, but you don't have to put it in your view model, or your control code-behind.

I would write a Behavior (called something like SelectListBoxItemWhenClickedBehavior) that when the button is clicked, it looks up the ListBoxItem in the visual tree (using VisualTreeHelper). It can then set ListBoxItem.IsSelected = true.

The behavior does one known thing and it is set only by the visual style of the control (XAML) which knows that the button is inside a ListBoxItem. I think this keeps the separation of concerns in place for M-V-VM.

If you need help writing a behavior, let me know.

Upvotes: 2

Related Questions