Width of items in ItemsControl - c#

I have an ItemsControl with a DataTemplate that is bound to an ObservableCollection of integers.
<ItemsControl Name="DimsContainer" ItemTemplate="{StaticResource DimensionsTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
And in the Windows Resources:
<Window.Resources>
<DataTemplate x:Key="DimensionsTemplate" >
<TextBlock Text="{Binding}"
Padding="5"
VerticalAlignment="Center"
FontSize="32"/>
</DataTemplate>
</Window.Resources>
My problem is that in code, I need to be able to determine the width of the TextBlocks (or whatever the element is if I change it later) in the ItemsControl. Does anyone have an idea how to do this?
When I do DimsContainer.Items[i] it gives me the bound item not the TextBlock.

You should be able to use instead:
DimsContainer.ItemContainerGenerator.ContainerFromIndex(i);
This won't give you the TextBlock itself, but it will give you the generated ContentPresenter that is wrapped around it by the ItemsControl to contain the ItemTemplate.

Related

WPF bind to property of the ItemsPanel of an ItemsControl

I've written a code example below:
<StackPanel>
<TextBlock>Appointments today</TextBlock>
<ItemsControl ItemsSource="{Binding Appointments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:CalendarMonthDayEventsItemsPanel OutsideViewportCount="..." />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<TextBlock Text="{Binding Title}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock>+</TextBlock>
<TextBlock Text="{Binding ......}" /> <!-- Should show number of items in ItemsControl that are outside view, using CalendarMonthDayEventsItemsPanel.OutsideViewportCount -->
<TextBlock>more items</TextBlock>
</StackPanel>
</StackPanel>
I Created a custom Panel, the CalendarMonthDayEventsItemsPanel, and I use that panel as the itemspanel of the ItemsControl. In the panel's layout code, I determine how many items (panel childs) are outside the bounds of the panel. The property OutsideViewportCount contains the number of items that are outside of the visible bounds of the CalendarMonthDayEventsItemsPanel.
Now I want to show the value of OutsideViewportCount in a TextBlock that's below the ItemsControl.
This means I have to create some kind of binding, but everything I tried doesn't work.
Does someone have a solution or a better approach to achieve the same result?
Maybe you can make use of Tag property of ItemsPanel to relay the value of ItemsPanel as a workaround.
<ItemsControl x:Name="A"
ItemsSource="{Binding Appointments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:CalendarMonthDayEventsItemsPanel OutsideViewportCount="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=Tag, Mode=OneWayToSource}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
...
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock>+</TextBlock>
<TextBlock Text="{Binding ElementName=A, Path=Tag, Mode=OneWay}"/>
<TextBlock>more items</TextBlock>
</StackPanel>

Prevent resize of the control that contains an ItemControl when there are no element in itemsSource in WPF without using fixed values

I have a ScrollViewer that contains an ItemsControl where the ItemsSource could be empty. I want to prevent that the ScrollViewer changes its height when ItemsSource is empty without using a fixed value.
This is the code:
<ScrollViewer
Grid.Row="1"
Grid.Column="1"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<ItemsControl
ItemsSource="{Binding ExperimentPresets}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="viewModels:ExperimentPresetInProcedureViewModel">
<askTouch:ComposingProcedureItemView/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal"
Margin="0 8 0 24"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
Does anyone have any ideas to solve this problem?
Thank you

Unable to bind collection to ComboBox in silverlight

I've a ObservableCollection, when I want to display this ObservableCollection with CheckBox I am simply binding the contents to CheckBox but when I want to display the same collection by using ComboBox I am unable to do that. Any suggestions?
XAML: Display collection using CheckBox --WORKS
<ItemsControl ItemsSource="{Binding Synonyms}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Margin="0,5,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Display items in CheckBox-->
<CheckBox Content="{Binding Display}" Margin="10,0,0,0" /> // Display is the collection.
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Output:
XAML: Display collection using ComboBox --NOTHING OVER HERE
<ItemsControl ItemsSource="{Binding Synonyms}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Margin="0,5,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Display items in ComboBox.-->
Approach - 1
<ComboBox>
<ComboBoxItem Content="{Binding Display}"/>
</ComboBox>
Approach - 2
<ComboBox ItemsSource="{Binding Path=Synonyms}" DisplayMemberPath="Display"/>
Approach - 3
<ComboBox >
<ComboBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Green" BorderThickness="1" Padding="5">
<TextBlock Text="{Binding Path=Display,StringFormat='Display: {0}'}" />
</Border>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Output:
I want to display items(one,two,three, etc.) inside oneComboBox with Select All option. I've tried several approaches but nothing. What am I missing here?
The checkbox is not designed to hold multiple items unlike the Combobox so implementing a system designed for the checkbox is not relevant for the combobox.
To solve your issue, remove the combobox from the ItemsControl and have it stand on its own:
<ComboBox ItemsSource="{Binding Synonyms}" DisplayMemberPath="Display"/>
Which tells the combobox to bind its ItemsSource to the data context which is unspecified, which is fine, so it then gets it's parent's data context. That process works its way up to each parent until it finds a bound data context (most likely the page's datacontext to a VM instance).
Assuming that the data context is valid at some point in the visual tree, it will bind to that instance and look for a property named Synonyms. From the Synonyms property it will use that as a list to display items.
To show (display) text in the combobox (instead defaulting to the item's ToString()) the combobox will show the string from the item's property Display.
Giving a list of items in one drop down.
The short answer, is you should use a ComboBox as the root element, not ItemsControl. CompboBox is just a specialized version of ItemsControl.
<ComboBox ItemsSource="{Binding Synonyms}" DisplayMemberPath="Display"/>
The longer answer.
ComboBox derives from ItemsControl, so you get all the features the base class, plus additional features.
ItemsControl (and its derived classes) provides a way of repeating a set of data in the UI. The DataTemplate is where you specify what UI you want for each "row" of data in the Synonyms source.
What you are doing is asking Silverlight to create a separate ComboBox for each underlying data row.
You can still use a DataTemplate within the ComboBox. Like this.
<ComboBox ItemsSource="{Binding Synonyms}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Display items in CheckBox-->
<TextBox Text="{Binding Display}"
Margin="10,0,0,0"
FontWeight="Bold" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Binding a list to a flow of WrapPanels

I am trying to do an interface in WPF where a list of item is displayed, taking as little vertical space as possible:
My instinct was to use an ItemsControl to bind my list, and to put the UI for each item into a WrapPanel. Unfortunately by default, each item starts at a new line regardless of the window's size. Adding a StackPanel with Orientation="Horizontal" makes all items in a single line, regardless of the size...
<!--<ScrollViewer Grid.Row="0" Grid.Column="0"
VerticalScrollBarVisibility="Auto">-->
<ItemsControl Margin="0,4" ItemsSource="{Binding Path=Watchers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type Core:Watcher}">
<WrapPanel Orientation="Horizontal">
<TextBlock Margin="0,2" Text="{Binding Path=Name}"
Width="250px" />
<TextBox Text="{Binding Path=Value, Mode=OneWay}"
Width="300px">
</TextBox>
</WrapPanel>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
<!--</ScrollViewer>-->
Any pointers?
Bonus point: Where should I add a ScrollViewer in order to have the behavior shown in my mockup?
Thanks a lot!
The WrapPanel has, as well as the StackPanel, an Orientation property, which defaults to Vertical. So your list should wrap (assuming you have enough space at hand) if your ItemsPanelTemplate looks like this:
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
About the ScrollViewer:
The desired behavior should be achieved by defining it like follows (not tested though, and I omitted all for this example unnecessary stuff):
<ScrollViewer HorizontalAlignment="Stretch">
<ItemsControl MinWidth="550" Width="{Binding ActualWidth, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}}}" />
</ScrollViewer>
I think you want the WrapPanel in the ItemsPanel and the StackPanel in the ItemTemplate.
why not use the WrapPanel as ItemsPanelTemplate?
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
as long as the items have space to the left they would be arranged horizontal.

WPF Databinding stackpanel

Im a beginner in WPF programming, coming from .NET 2.0 C#.
Im trying to make a horizontal StackPanel which should be filled with data from a table in a database. The problem is that I want it to display an image with some text from the table below and then stack those two items horizontally.
Here's some pseudo-code to display what I want to do:
<StackPanel Orientation="horizontal" ItemsSource="{Binding Path=myTable}">
<StackPanel>
<Image Source="User.png"/>
<Label HorizontalAlignment="Center" Content="{Binding Path=UserName}"></Label>
</StackPanel>
</StackPanel>
I simply cannot figure oout how to do this.
Julien's answer is correct for your written description, however, looking at your XAML, it appears you are looking for something like the following:
<DataTemplate x:Key="UserDataTemplate">
<StackPanel>
<Image Source="User.png"/>
<Label HorizontalAlignment="Center" Content="{Binding Path=UserName}" />
</StackPanel>
</DataTemplate>
<ItemsControl x:Name="UserList" ItemTemplate="{StaticResource UserDataTemplate}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
You definately need an ItemsControl (or some derivation of) to bind your source to. Then you can change the the orientation by setting it's items panel (which I believe is a VirtualizingStackPanel with Vertical orientation by default) so just set it to a VirtualizingStackPanel with Horizontal Orientation. Then you can set the ItemsTemplate for each of your items to the layout you desire (an image stacked on top of text bound from your database).
Basically, you want to use a control capable of displaying an enumeration of objects. The control capable of this is the class ItemsControl and all of its descendants (Selector, ListBox, ListView, etc).
Bind the ItemsSource property of this control to a list of objects you want, here a list of users you've fetched from the database. Set the ItemTemplate of the control to a DataTemplate that will be used to display each item in the list.
Sample code:
In a Resources section (for example Window.Resources):
<DataTemplate x:Key="UserDataTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="User.png"/>
<Label HorizontalAlignment="Center" Content="{Binding Path=UserName}" />
</StackPanel>
</DataTemplate>
In your Window/Page/UserControl:
<ItemsControl x:Name="UserList" ItemTemplate="{StaticResource UserDataTemplate}" />
In your code behind:
UserList.ItemsSource = ... // here, an enumeration of your Users, fetched from your db

Categories