I'm attempting to use the XAML C# Grouped GridView sample to make my SemanticZoom work in a XAML C# Windows 8 app. The problem is, for some reason it's displaying the correct header (the category, in this case), but it's not showing all the items under the header (it's only showing one for each, when I have up to 6 items in some of them).
Here's the SemanticZoom's XAML code (note that I left out the ZoomedOutView for brevity, and since it's working perfectly):
<SemanticZoom x:Name="boardZoom" Height="626" Margin="10,132,10,0" VerticalAlignment="Top">
<SemanticZoom.ZoomedInView>
<GridView IsSwipeEnabled="True" x:Name="ItemsGridView" Tapped="Tapped" ItemsSource="{Binding Source={StaticResource cvs2}}" SelectionChanged="selChanged">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10,10,0,0"
HorizontalAlignment="Left" VerticalAlignment="Stretch">
<Image Source="{Binding Thumbnail}"></Image>
<TextBlock Text="{Binding Title}" TextWrapping="Wrap" Width="500"
FontFamily="Global User Interface" FontSize="40" VerticalAlignment="Top" />
<TextBlock Text="{Binding pinNumber}" x:Name="PinNum" Visibility="Collapsed"></TextBlock>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text='{Binding Key}' Foreground="White" Margin="5" FontSize="20" FontFamily="Segoe UI Light" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupItem">
<StackPanel Orientation="Vertical">
<ContentPresenter Content="{TemplateBinding Content}" />
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding GroupItems}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" MaximumRowsOrColumns="5" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Vertical" MaximumRowsOrColumns="1" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</SemanticZoom.ZoomedInView>
and the Refresh() C# function that's called when the app is started up:
System.Collections.ObjectModel.ObservableCollection<SemanticZoomed> finalSource = new System.Collections.ObjectModel.ObservableCollection<SemanticZoomed>();
public async Task<bool> Refresh()
{
var Pins = await pinTable.ReadAsync(); //pinTable is an Azure Mobile Services table
List<string> categoriesMixed = new List<string>();
if (Pins.ToArray().Length < 1)
{
//adds a new "Welcome" pin to the table, taken out for brevity
}
foreach (pin nowPin in Pins)
{
SemanticZoomed toAdd = new SemanticZoomed();
toAdd.Category = nowPin.category;
toAdd.pinNumber = nowPin.Id.ToString();
toAdd.Title = nowPin.name;
categoriesMixed.Add(nowPin.category);
finalSource.Add(toAdd);
}
List<GroupPinList<object>> groups = new List<GroupPinList<object>>();
var query = from nowPin in finalSource
orderby ((SemanticZoomed)nowPin).Category
group nowPin by ((SemanticZoomed)nowPin).Category into g
select new { GroupName = g.Key, Items = g };
foreach (var g in query)
{
GroupPinList<object> info = new GroupPinList<object>();
info.Key = g.GroupName;
foreach (var item in g.Items)
{
info.Add(item);
}
groups.Add(info);
}
cvs2.Source = groups;
(boardZoom.ZoomedOutView as ListViewBase).ItemsSource = cvs2.View.CollectionGroups;
return true;
}
And here are a few screenshots of what the groups variable looks like, and what the resulting SemanticZoom shows:
the groups variable:
the "Welcome" category in the groups variable (it correctly shows its 6 items, and also the error "Cannot fetch the value of field 'imgSrc' because information about the containing class is unavailable" next to imgSrc, which disappears in cvs2 below):
cvs2 (it shows the 6 different items under the Welcome category):
and finally, what it ends up displaying:
I'm at a loss as to where those other pins in the Welcome category went. Is there something in the XAML code that I'm missing? Any help would be much appreciated :)
I have the same problem . And this at resolved the pb .
In the SemanticZoom.ZoomedInView replace
<ItemsPanelTemplate>
<WrapGrid Orientation="Vertical" MaximumRowsOrColumns="1" />
</ItemsPanelTemplate>
by
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
I think I know where's the problem - this happens if you are adding items to the GridView programatically group after group. What happens here is when you add the first group with n items to the GridView source, then number n is kept and for each group added afterwards it shows no more than n items, even though there is more items.
So if you have 5 groups in collection with 2,4,1,5,3 items, you assign empty ObservableCollection as the ItemSource of the GridView and then you add in foreach these groups into the ObservableCollection, you will see only 2,2,1,2,2 items in each group.
I don't know why this is happening, if it's feature or a bug, but you can solve it either by loading the ObservableCollection first and then assigning it to the GridView as a source, or you can use some kind of converter, that will return for each group same number of items. For groups with lesser number you then add fake empty items and hide them using different DataTemplate.
Edit: I've just noticed you are already adding the collection at once, so the problem is probably elsewhere. Maybe the root you your issue is this in ItemsPanel?
MaximumRowsOrColumns="1"
you need to use stackpanel instead of WrapGrip in ItemPanelTemplate
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
Related
I'm trying to make my xaml squeeze list items (images) to fit the initial window size, but they cant be fixed size because i want to scale them up as i increase the size of the window. Something like a ViewBox would do.
I load images from 2 folders (software and hardware). Number and size of the images will wary in the runtime so i want to make items be the same size regardless of images size or number of items.
That's why i used uniform grid as a items panel template.
But, this is the result I'm getting...
The ListView loads images in their full size and expands itself to fit them in, cutting of some of the items in the process.
This is my xaml:
<Window x:Class="WPF_UI_Testing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF_UI_Testing"
mc:Ignorable="d"
Title="MainWindow" Height="460" Width="640">
<Grid>
<ListView x:Name="listview1">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"
FontWeight="Bold" FontSize="18" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid ></UniformGrid>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding problemImage}"/>
<TextBlock Text="{Binding ImageName}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
Is there a way to prevent ListView from expanding beyond window borders when populated with content?
EDIT:
I packed the entire solution with some dummy data and images if anyone wants to have a go at this...
https://drive.google.com/file/d/1IWqxSR3kpsVdCm5Qcgn6QZbZhbYz52n2/view?usp=sharing
The UniformGrid does basically what you want. The idea to use it as item panel is also correct. The only problem that arises, aside from using item groups, is the fact that the ListView wraps its panel into a ScrollViewer, which results in items or the UniformGrid to resize differently as the ScrollViewer gives the panel no size restrictions. UniformGrid needs to be hosted in a fixed size container in order to be able to calculate its children's max sizes.
You should either use the ItemsControl
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type viewModels:DetailItem}">
<StackPanel>
<Image Source="{Binding problemImage}"/>
<TextBlock Text="{Binding ImageName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
or override the ControlTemplate of ListView and remove the ScrollViewer (if you need its additional features of ListView):
<ListView>
<ListView.Template>
<ControlTemplate TargetType="ListView">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<ItemsPresenter />
</Border>
</ControlTemplate>
</ListView.Template>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type viewModels:DetailItem}">
<StackPanel>
<Image Source="{Binding problemImage}"/>
<TextBlock Text="{Binding ImageName}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The limitations of this approach is when using groups to display the items. UniformGrid should handle GroupItem (nested items) not as expected.
As said in my previous comment, if you want to group items, you need to extend a panel of your choice to manually arrange GroupItem and it's children (nested ItemsPresenter). As you think about how to calculate sizes you may realizes that it is more complicated to calculate group item sizes with dynamic grouped item sizes.
I recommend to let go the grouping and use one of the above solutions or use grouping and embrace the ScrollViewer.
I have a situation where I want to see a queue of items related to another list. I want to arrange the parent items vertically and the child items horizontally. So Far I have the following:
Parent:
<ListBox x:Name="listResources" ItemsSource="{Binding Resources}" >
<ListBox.ItemTemplate>
<DataTemplate>
<local:ResourceControl x:Name="resources" thisResource="{Binding Path=.}" Margin="2"></local:ResourceControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My Child items:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="ListBox">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="3">
</StackPanel>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<StackPanel Grid.Column="0">
<TextBlock FontSize="20" x:Name="labelResourceName" Text="{Binding ResourceName}"></TextBlock>
</StackPanel>
<ListBox Grid.Column="1" x:Name="listOperations" ItemsSource="{Binding Operations}" >
<ListBox.ItemTemplate>
<DataTemplate>
<local:OperationControl x:Name="operations" thisOperation="{Binding Path=.}" Margin="2" ></local:OperationControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
This works relatively well and gives me my child items listed horizontally as I want them to be. The problem is that I need to be able to scroll the child items individually. As it is written currently I have the ability to scroll horizontally, but all of the child items scroll together.
I have attempted to wrap the parent listbox inside a but that did not seem to do it either.
How can I get the items inside of the listbox to scroll individually instead of all together as a group?
I found the answer to this issue. The problem was that I had not defined a width for the listboxes. Once I added widths to the controls the scrolling worked properly.
I'm binding data to my ZoomedOut semantic zoom as so:
var result = from title in _allTitles group title by title._titleSubject into grp orderby grp.Key select grp;
groupedTitlesSource.Source = result;
(semanticZoom.ZoomedOutView as ListViewBase).ItemsSource = groupedTitlesSource.View.CollectionGroups;
And am accessing the Key using Group.Key but I also want to access the first item in the group, what's the easiest way of doing this? My Xaml is below for the ZoomedOutView:
<SemanticZoom.ZoomedOutView>
<GridView x:Name="zoomedOutGridView" HorizontalAlignment="Center">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="210" Height="140" Background="#CC196CFF">
<TextBlock
Text="{Binding Group.Key}"
FontFamily="Segoe UI Light"
FontSize="24"
Foreground="White"
VerticalAlignment="Top"/>
<!-- Also want to access the first item in the group here -->
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</SemanticZoom.ZoomedOutView>
Any help would be great, and I'm very new to this so simple as possible :)
Thanks
In the first place your Group.Key should be in the GridView.GroupStyle and your items should be under GridView.ItemTemplate. With that you will be able to access to the group items itself.
I'm kind of shooting in the dark on this one and have been looking around but couldn't find much of anything related. Pretty much I am trying to create an ItemsControl on a current Window that I've got, so when the user clicks an "Add Product" button on the window, it will add a UserControl to the screen in a horizontal matter.
For starters I am using an MVVM pattern and I have a PricingViewModel which is my ViewModel for the MAIN window. I have a second view model named ComparisonViewModel, which is the ViewModel for the View of the UserControl that I would like to show everytime the user hits the "Add Product" button on the PricingView. Jumping into my code, I've got a declared ObservableCollection and my AddComparison method. The Collection is instantiated in the constructor of the VM.
public ObservableCollection<ComparisonViewModel> Products { get { return _products; } }
public void AddComparison()
{
var products = IoC.Get<ComparisonViewModel>();
Products.Add(products);
}
Next, I've got and ItemsControl in the PricingView that binds to that collection in the PricingViewModel:
<ItemsControl ItemsSource="{Binding Path=Products}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
I run it and after hitting add, it just shows the collection name. How can I actually get it to Pop up with a new Comparison User Control when the user hits Add Comparison? Thanks a ton for the help in advance!
You'll want to set the ItemTemplate so the ItemsControl knows how to render each item in the collection (by default, it is just displaying the result of calling .ToString()).
<ItemsControl ItemsSource="{Binding Path=Products}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type namespace:ComparisonViewModel}">
<!-- EXAMPLE -->
<Border BorderBrush="Black"
BorderThickness="2">
<DockPanel Orientation="Horizontal">
<TextBlock Text="{Binding ComparisonResult}"
DockPanel.Dock="Right" />
<TextBlock Text="{Binding Name}"
DockPanel.Dock="Left" />
</DockPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have found that I needed to tell the ItemsControl two things... First is what type of "thing" the ItemsControl is:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
And the second is how to display the Control:
<ItemsControl.ItemTemplate>
<DataTemplate>
<c:Widget Margin="5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
The final code looks like:
<ItemsControl ItemsSource="{Binding Path=DynamicItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<c:Widget Margin="5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You also need to add a reference to your control namespace in the window declaration stuff:
xmlns:c="clr-namespace:IHateEverything.Controls"
For a windows 8 application in C#/XAML, I would like to be able to know the position (X and Y) of a button that I have in the header template of a grouped grid View:
Here is the simple Xaml Code :
<GridView x:Name="PicturesGridView" SelectionMode="None"
ItemsSource="{Binding Source={StaticResource cvs1}}" IsItemClickEnabled="True"
ItemTemplate="{StaticResource CustomTileItem}" ItemClick="ItemView_ItemClick" IsSwipeEnabled="True">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</local:MyGridView.ItemsPanel>
<local:MyGridView.GroupStyle>
<GroupStyle x:Name="MyGroupStyle">
<GroupStyle.HeaderTemplate >
<DataTemplate x:Name="MyDataTemplate">
<Button x:Name="HeaderButton" Click="Button_Click_1" Content="{Binding Key}" Foreground="Black" Background="White" FontSize="30" Margin="0,0,0,-10" ></Button>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid ItemWidth="75" ItemHeight="150" Orientation="Vertical" Margin="0,0,80,0" MaximumRowsOrColumns="3"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
<GridView.GroupStyle>
<GridView>
I succeed in accessing to the Button inside the header template by doing this :
var template = element.FindName("PicturesGridView") as MyGridView;
var group = template.GroupStyle[0] as GroupStyle;
var buttonHeader = group.HeaderTemplate.LoadContent() as Button;
But then I can't distinguish each button of my template. I would like an array of physical button representing my data and their position.
Thank you for your help
The WinRT Tookit has what you need...Check out http://winrtxamltoolkit.codeplex.com/downloads/get/467926 and look at the VisualTreeHelperExtensions.
Using the extension method GetDescendantsOfType you can write code like the following:
var buttons = PicturesGridView.GetDescendantsOfType().ToArray();
Now, this will give you all the buttons in PicturesGridView, so if you have item templates that also contain buttons, you will get those as well. You could set the Tag property on the button in the Header template so you could easily identify them from other buttons.