I have a view model containing an observable collection property:
public ObservableCollection<ExplorerPane> Panes { get; set; } = new ObservableCollection<ExplorerPane>();
In the user control corresponding to my view model, I am using Panes as the ItemsSource to an ItemsControl and just using a ContentPresenter to display the content of each ExplorerPane:
<ItemsControl ItemsSource="{Binding Panes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The catch is that I want the content presenters to render their panes on top of each other, so that only one is visible at a time.
I have thought of a solution along these lines: "Controls in the same cell of a Grid are rendered back-to-front. So a simple way to put one control on top of another is to put it in the same cell."
My question then is how do I get the content presenters to be in the same cell of a grid?
Use a Grid as ItemsPanel:
<ItemsControl ItemsSource="{Binding Panes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
The ItemTemplate isn't necessary, because an ItemsControl already uses a ContentPresenter as item container.
However, if you only want to show a single ExplorerPane, add a CurrentPane property to your view model, and show it by
<ContentControl Content={Binding CurrentPane}"/>
Related
I have an ItemsControl with ListViews inside to make a custom grid like layout
Here is roughly what the code looks like to do this, names changed and irrelevant styling is removed.
Each ListView is created by an instance of ItemsSubList and therefore there is no set amount of listboxes or properties to be made.
Does anyone know How I would be able to bind the SelectedItem property of each listbox out somehow, into a list preferably.
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding ItemsSubList}"
DisplayMemberPath="ItemVersion"
SelectionMode="Single"
Width="100"
VerticalAlignment="Top"
Background="#282828"
BorderBrush="#282828">
</ListView>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I would solve it in your Model.
Your datacontext seems to be a class with a property Items of type ObservableCollection<MyItem> and your class MyItem then as a property ItemsSubList of type ObservableCollection<MySubItem>. Is that right?
The datacontext of your ListView is the instance of type MyItem. You can add a Property SelectedSubItem to your class MyItem and bind it with Two-way-binding to your listbox.SelectedItem.
And then in your main class, that holds your model and where the property Items lives, there I would add a property
public List<MySubItem> SelectedSubItems => Items.Select(i => i.SelectedSubItem).ToList();, a property that dynamically selects all selected subitems from all your items.
Here's the scenario: I have a flickr photo viewer, and the PhotoBrowserViewModel has a property named Image Source. The View that is bound to my PhotoBrowserViewModel contains the following XAML.
My goal is to get the child controls to have the height/width of the ImageSource property.
<ItemsControl ItemsSource="{Binding Photos}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="viewmodel:FlickrPhotoViewModel">
<controls:FlickrPhotoControl Margin="10"/>
<!-- I want to set this control's Width/Height to {Binding PhotoSize}-->
<!-- on the same data context as ItemsControl, not as the data template.-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Use relative source binding:
{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}, Path=DataContext.PhotoSize}
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.
I may just be missing something obvious here, so I apologize if this is a really dumb question. I have a WrapPanel in a view that I need to bind to an ObservableCollection on the ViewModel. This ObservableCollection contains a different type of ViewModel that needs to be bound to another type of view when displayed in the WrapPanel. The goal is to create a wrappable list of items, each of which displays via an instance of a smaller view which should be added to the WrapPanel.
I am using MVVM, and the ViewModel does not have direct access to the View. I would rather not create a binding between the ViewModel and the View if at all possible, so manually adding items to the WrapPanel.Children collection is not a viable option. I am at a loss as to how I can bind a collection of child ViewModel objects to the WrapPanel in such a way that it will create instances of another view and add them to itself. Am I simply approaching the problem incorrectly? I figure there is probably a DataTemplate involved, but it doesn't appear that a WrapPanel has a DataTemplate, nor is it bindable.
Thanks for any insight.
What you need is a ListView that uses a WrapPanel to host all of the items.
<ListView ItemsSource={...}>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<!-- Fill in how you want each item to look here -->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Use an ItemsControl, and set its ItemsPanel to a WrapPanel:
<ItemsControl ItemsSource="{Binding Something}" ItemTemplate="{StaticResource YourDataTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
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