Binding inside listbox itemtemplate problems

12,182

Solution 1

The problem is that the two-way binding on the source itself cannot work because it would mean that the whole object (string), for which the data template is created, must be replaced when user changes the text in the text box. Obviously, this will not work. Two-way binding will work only on a writable property of the bound object.

In your case I would suggest creating a view model for the items in the list box (basically a view model for your strings) and expose a Value property on it and bind to it in the data template:

<ListBox Height="231" HorizontalAlignment="Left" Margin="0,167,0,0" 
         Name="listBoxKeys" VerticalAlignment="Top" Width="219" 
         ItemsSource="{Binding Path=SelectedPlatform.KeyViewModels}" 
         SelectedItem="{Binding Path=SelectedKey,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
        <ListBox.ItemTemplate>
             <DataTemplate>
                 <StackPanel Orientation="Horizontal" Margin="0,0,0,0">
                    <TextBox Text="{Binding Value, Mode=TwoWay}" Margin="0,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
                  </StackPanel>
              </DataTemplate>
         </ListBox.ItemTemplate>
</ListBox>

Solution 2

1) Pavlo Glazkov seems to have a good answer to me

2) This is down to the DataContext for the ComboBox now being the key value pair rather than the ViewModel. There may be other ways to do this but the one that I've used before is to set the bindings RelativeSource source back to it's parent ItemsControl.

RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}

Something like:

<ListBox Height="393" HorizontalAlignment="Left" Margin="0,72,0,0" Name="listBoxActions" VerticalAlignment="Top" Width="254" ItemsSource="{Binding Path=SelectedPlayer.ControlProfile.MappedActions}">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Horizontal" Margin="0,0,0,0">
          <TextBox Text="{Binding Key, Mode=TwoWay,UpdateSourceTrigger=LostFocus}" Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
          <ComboBox Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center" ItemsSource="{Binding DataContext.Keys,  RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" SelectedItem="{Binding Value, Mode=TwoWay}"/>
         </StackPanel>
        </DataTemplate>
       </ListBox.ItemTemplate>
</ListBox>
Share:
12,182
muku
Author by

muku

Updated on June 04, 2022

Comments

  • muku
    muku almost 2 years

    I have two separate binding problems with listboxes with an itemtemplate which contains a texbox.

    1) One listbox binds to a list of strings. How can I display each string inside the textboxes created and allow two way binding at the same time? Two way binding isn't allowed without specifying a Path or XPath.

    <ListBox Height="231" HorizontalAlignment="Left" Margin="0,167,0,0" Name="listBoxKeys" VerticalAlignment="Top" Width="219" ItemsSource="{Binding Path=SelectedPlatform.Keys}" SelectedItem="{Binding Path=SelectedKey,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
             <ListBox.ItemTemplate>
                  <DataTemplate>
                      <StackPanel Orientation="Horizontal" Margin="0,0,0,0">
                         <TextBox Text="{Binding Mode=OneWay}" Margin="0,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
                       </StackPanel>
                   </DataTemplate>
              </ListBox.ItemTemplate>
     </ListBox>
    

    And 2) I use another listbox which binds to some generic list of a custom KeyValuePair class. The itemtemplate contains a textbox and combobox. The textbox text is bound to the key property of each KeyValuePair object and the combobox selecteditem to the value property. My problem is that I want the combo to get filled by a list of strings declared in my viewmodel which will be changing on runtime. The window's datacontext is the viewmodel where the list is declared. I don't know the exact syntax I need to use to bind the combobox itemssource there. Here's my code :

    <ListBox Height="393" HorizontalAlignment="Left" Margin="0,72,0,0" Name="listBoxActions" VerticalAlignment="Top" Width="254" ItemsSource="{Binding Path=SelectedPlayer.ControlProfile.MappedActions}">
        <ListBox.ItemTemplate>
          <DataTemplate>
            <StackPanel Orientation="Horizontal" Margin="0,0,0,0">
              <TextBox Text="{Binding Key, Mode=TwoWay,UpdateSourceTrigger=LostFocus}" Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
              <ComboBox Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center" ItemsSource="{Binding ?}" SelectedItem="{Binding Value, Mode=TwoWay}"/>
             </StackPanel>
            </DataTemplate>
           </ListBox.ItemTemplate>
    </ListBox>
    
  • muku
    muku over 13 years
    So your code is looking for the items of the listbox. But that's not what i need. If you see the ItemsSource of the listbox is bound to SelectedPlayer.ControlProfile... SelectedPlayer is a property of my viewmodel. I have another property named Keys in the viewmodel. That's where I want to bind the ItemsSource of the combobox :)
  • bmb8lco
    bmb8lco over 13 years
    @muku - My bad... was missing one vital part of the puzzle. Check out my latest update to the sample. I've changed the path to DataContext.Keys
  • muku
    muku over 13 years
    Thanks for that. I created a useless class called ControllerKey which has a string property Name. So right now my SelectedPlatform.Keys is a generic list of type ControllerKey instead of string. That way I overcame my problem :)
  • muku
    muku over 13 years
    Hey thanks :) That worked. Could you point me to a good tutorial on what i need to do in order to update the items of the combobox after the Keys list is updated? I don't want to put you in trouble asking for more examples, I could take a look at a good tutorial. (I am a newbie in wpf)
  • bmb8lco
    bmb8lco over 13 years
    @muku - No problem muku. Not really sure what you are after here. If you want to assign the values for Keys after the control has been created then your ViewModel needs to implement INotifyPropertyChange and all you need to do is raise a PropertyChangeEvent msdn.microsoft.com/en-us/library/ms743695.aspx. If the list of Keys is changing internally, i.e. items being added and removed, then you probably want to check out ObservableCollections msdn.microsoft.com/en-us/library/ms748365.aspx. This behaviour would be a bit odd for a combo box though ;)