descala
Topic Author
Posts: 15
Joined: 19 Sep 2013, 20:11

Binding to a TextBox inside a Style for a ListBoxItem

30 May 2014, 02:25

Hi!

I'm having a bit of trouble adding items to a listbox for which I've made an item style.

The idea is that a TextBox contained within the style should be bound to a property of my data items, in this case ModelName. I set the binding to ModelName inside the TextBox, set the ItemsSource property for the ListBox, as well as the item container style, and a DataContext containing items which expose a ModelName property, but this approach is failing. The listbox does get populated as I add items to it, but my textboxes are blank. I tried using a two-way binding, but that did not work either.

To start with, here is my list box item style:
		<Style x:Key="ListBoxItemModelLayerStyle" TargetType="{x:Type ListBoxItem}">
			<Setter Property="Background" Value="Transparent"/>
			<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
			<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
			<Setter Property="Padding" Value="2,0,0,0"/>
			<Setter Property="Template">
				<Setter.Value>
					<ControlTemplate TargetType="{x:Type ListBoxItem}">
						<Grid x:Name="GridTemplate" HorizontalAlignment="Stretch" Height="60" Margin="0" VerticalAlignment="Top" Width="168" Visibility="Visible">
							<Rectangle x:Name="RectangleTemplate" RadiusY="5" RadiusX="5" Fill="#BF6C87CC"/>
							<TextBox x:Name="ModelNameTextBoxTemplate" Margin="32.5,5,0,0" TextWrapping="Wrap" Text="{Binding ModelName}" FontSize="12" Background="#FF5368A1" Foreground="#FFDADADA" Height="25" VerticalAlignment="Top" Width="130" HorizontalAlignment="Left" BorderBrush="{x:Null}"/>
							<ComboBox x:Name="ModelTypeComboBoxTemplate" Height="24" Margin="32,0,0,5" VerticalAlignment="Bottom" Width="79" HorizontalAlignment="Left" Background="#FF6781C3" Foreground="Black" BorderBrush="{x:Null}">
								<ComboBoxItem x:Name="ModelTypeBoxUpperTemplate" Content="Upper"/>
								<ComboBoxItem x:Name="ModelTypeBoxLowerTemplate" Content="Lower"/>
								<ComboBoxItem x:Name="ModelTypeBoxBuccalTemplate" Content="Buccal"/>
							</ComboBox>
							<ToggleButton x:Name="ModelToggleVisibilityButtonTemplate" Content="ToggleButton" HorizontalAlignment="Left" Margin="3,0,0,0" Style="{DynamicResource ToggleVisibilityEye}" Width="25" IsChecked="True" VerticalAlignment="Center" Height="25"/>
						</Grid>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
... and here is the ListBox to whose items it is applied ...
				<ListBox x:Name="ItemLayersListBox" ItemsSource="{Binding Items}" HorizontalAlignment="Center" Margin="0" Width="200" VerticalAlignment="Center" MaxHeight="720" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden" MinHeight="200">
					<ListBoxItem Content="ModelLayer" Style="{DynamicResource ListBoxItemModelLayerStyle}"/>
				</ListBox>
Here are my data context and items wrapper classes:
    class DataModel : public Noesis::Core::BaseComponent
    {
    public:
        DataModel() : items_(new Noesis::Gui::Collection())
        {    }
        ~DataModel()
        {
            
        }
        
        Noesis::Gui::Collection* GetItems() const { return items_; }
        
        
    private:
        Noesis::Gui::Collection* items_;
        
        NS_IMPLEMENT_INLINE_REFLECTION(DataModel, Noesis::Core::BaseComponent)
        {
            NsMeta<Noesis::Core::TypeId>("DataModel");
            NsProp("Items", &DataModel::GetItems);
        }
    };
    struct DataItem : public Noesis::Core::BaseComponent
    {
        DataItem(const NsChar* n) :
        name_(n)
        {
        }
        
        NsString name_;
        NsString type_;
        
        NS_IMPLEMENT_INLINE_REFLECTION(DataItem, Noesis::Core::BaseComponent)
        {
            NsMeta<Noesis::Core::TypeId>("DataItem");
            NsProp("ModelName", &DataItem::name_);
        }
    };
and here is where I initialize my listbox, set data context and item style:
        auto list_box = NsStaticCast<ListBox*>(gui_root_->FindName(LISTBOX_NAME.c_str()));
        
        data_model_ = new DataModel();
        
        Ptr<IResourceKey> key = ResourceKeyString::Create("ListBoxItemModelLayerStyle");
        Noesis::Gui::Style* style = gui_root_->FindResource<Noesis::Gui::Style>(key.GetPtr());
        list_box->SetDataContext(data_model_);
        list_box->SetItemContainerStyle(style);
When I add items, I do the following:
        data_model_->GetItems()->Add(new DataItem(_name.c_str()));
This creates a new DataItem with a ModelName property, which should be bound to the textbox. However, I cannot get this to work. If I use a DataTemplate rather than a Style, the binding works, but I have other problems.

Any ideas?
Thanks
 
User avatar
sfernandez
Site Admin
Posts: 3013
Joined: 22 Dec 2011, 19:20

Re: Binding to a TextBox inside a Style for a ListBoxItem

30 May 2014, 11:17

Hi,

First of all, if you use the ItemsSource property, the ListBox.Items collection is made read only and you cannot add/remove items from there, so you shouldn't specify any ListBoxItem children inside the ListBox. The following xaml is wrong (we will add the corresponding error message in a following version):
<ListBox ItemsSource="{Binding Items}" ...>
    <ListBoxItem .../>  <!-- WRONG -->
</ListBox>
Second, when you use the ItemsSource property, a ListBoxItem container is automatically created for each item, so if you want to specify a Style for these containers, you have to do it using ItemContainerStyle property:
<ListBox
    ItemsSource="{Binding Items}"
    ItemContainerStyle="{StaticResource ContainerStyle}" .../>
Next, to understand how data binding works in a ListBox I made this graphic representing the generated visual tree:
ListBox Visual Tree.png
As you can see, your DataItems are connected through the DataContext property to the root of the DataTemplate you specify in the ItemTemplate property. The ListBoxItem and its template elements know nothing about the DataItem, so they cannot have a Binding to DataItem properties. These bindings only work for elements in the ItemTemplate's DataTemplate.

Which problems do you have when using a DataTemplate?
 
descala
Topic Author
Posts: 15
Joined: 19 Sep 2013, 20:11

Re: Binding to a TextBox inside a Style for a ListBoxItem

30 May 2014, 16:40

Thank you for the very detailed explanation!

So it looks as though using a Style will not work for my purposes, as I need the fields bound to item properties.

Regarding DataTemplates, when I was using a DataTemplate containing a styled ToggleButton, the style wasn't being properly applied to the ToggleButton when I dynamically added items to the listbox.

Here is the DataTemplate I was using before (the ToggleButton Style below is ToggleVisibilityEye):

<DataTemplate x:Key="ModelLayerTemplate">
	<Grid HorizontalAlignment="Left" Height="60" Margin="0,0,0,0" VerticalAlignment="Top" Width="190">
		<Rectangle RadiusY="5" RadiusX="5" Fill="#BF95ACE5"/>
		<TextBox x:Name="ModelNameTextBox" Margin="32.5,5,0,0" TextWrapping="Wrap" Text="{Binding ModelName}" FontSize="12" Background="#FF5368A1" Foreground="#FFDADADA" Height="25" VerticalAlignment="Top" Width="130" HorizontalAlignment="Left" BorderBrush="{x:Null}"/>
		<ComboBox x:Name="ModelTypeComboBox" Height="24" Margin="32,0,0,5" VerticalAlignment="Bottom" Width="79" HorizontalAlignment="Left">
			<ComboBoxItem x:Name="ModelTypeBoxUpper" Content="Upper" IsSelected="True"/>
			<ComboBoxItem x:Name="ModelTypeBoxLower" Content="Lower"/>
			<ComboBoxItem x:Name="ModelTypeBoxBuccal" Content="Buccal"/>
		</ComboBox>
		<ToggleButton x:Name="ModelToggleVisibilityButton" Content="ToggleButton" HorizontalAlignment="Left" Margin="3,0,0,0" Style="{DynamicResource ToggleVisibilityEye}" Width="25" IsChecked="True" VerticalAlignment="Center" Height="25"/>
	</Grid>
</DataTemplate>
That Style uses a stroked path graphic to toggle the visibility of items referenced in the listbox. But when applying the template to dynamically added items, I see a default-styled ToggleButton with some text that appears to say "To" (as in ToggleButton maybe?), rather than the properly styled button.

Is there something I'm doing wrong there in using the DataTemplate?
 
KeldorKatarn
Posts: 193
Joined: 30 May 2014, 10:26

Re: Binding to a TextBox inside a Style for a ListBoxItem

30 May 2014, 20:20

I'm not sure if I remember this right but... can't you declare that DataTemplate as a resource, and then in the style itself reference that datatemplate, assigning it not directly but in the style... would that work?
 
User avatar
sfernandez
Site Admin
Posts: 3013
Joined: 22 Dec 2011, 19:20

Re: Binding to a TextBox inside a Style for a ListBoxItem

01 Jun 2014, 10:58

Regarding DataTemplates, when I was using a DataTemplate containing a styled ToggleButton, the style wasn't being properly applied to the ToggleButton when I dynamically added items to the listbox.
Is there something I'm doing wrong there in using the DataTemplate?
I was able to reproduce the problem. There is a bug with DynamicResource look up. We will fix it in the next release. Meanwhile you can use a StaticResource instead:
<DataTemplate x:Key="ModelLayerTemplate">
   <Grid HorizontalAlignment="Left" Height="60" Margin="0,0,0,0" VerticalAlignment="Top" Width="190">
      ...
      <ToggleButton x:Name="ModelToggleVisibilityButton" Content="ToggleButton" HorizontalAlignment="Left" Margin="3,0,0,0" Style="{StaticResource ToggleVisibilityEye}" Width="25" IsChecked="True" VerticalAlignment="Center" Height="25"/>
   </Grid>
</DataTemplate>
 
descala
Topic Author
Posts: 15
Joined: 19 Sep 2013, 20:11

Re: Binding to a TextBox inside a Style for a ListBoxItem

06 Jun 2014, 16:28

Thanks! I'll try the StaticResource approach for now.
 
User avatar
sfernandez
Site Admin
Posts: 3013
Joined: 22 Dec 2011, 19:20

Re: Binding to a TextBox inside a Style for a ListBoxItem

01 Jul 2014, 14:41

DynamicResource look-up solved in 1.1.9 version.

Who is online

Users browsing this forum: Ahrefs [Bot], Semrush [Bot] and 1 guest