semantic zoom grouped data binding and accessing individual items - c#

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.

Related

WPF ListView->GridView->StackPanel

I have a ListView that uses GridView to display some data. One of the fields contains a list with image paths. Therefore I defin a GridViewColumn and create a DataTemplate. Dis DataTemplate contains another ListView with the Images list as new DataContext. When I don't write anything in the inner StackPanel, I can see that a list of string (in the format AppName.ClassName) is displayed in left to right order.
But whenever I try to display the strings as something else, eg
<Image Source="{Binding Name}" Height="32"/>
I get an System.Windows.Markup.XamlParseException . Even with data binding I get an exception. Eg
<Image Source="Images/Camera_32xLG.png" Height="32"/>
. Any hint, what I might do wrong?
<GridViewColumn Header="Images">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding Images}" BorderThickness="0">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
--> here is where I don't know what to do next
</StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Since the StackPanel is a part of ItemsPanelTemplate, you should just define it's properties and not explicitly add any children. The way to specify appearance of each item is through the ListView.ItemTemplate property:
<ListView ItemsSource="{Binding Images}" BorderThickness="0">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Name}" Height="32" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Tile Grid with Bindings?

OK, what I'm trying to do is fairly simple :
I'm getting a list of images (using bindings) which I'm trying to display in a table-like grid (like 3 images per row)
How can this be done?
<ListBox.ItemTemplate>
<DataTemplate>
<Image Height="100" Width="100" Margin="12,0,9,0" Source="{Binding AlbumArt}"/>
</DataTemplate>
</ListBox.ItemTemplate>
This way, the images are property display, but not the way I want them to - they are display one below the other and not like :
A B C
D E F
G H I
How can this be done? Any ideas?
A great solution would be using UniformGrid with its columns property and ItemsControl.
Example:
<ItemsControl ItemsSource="{Binding AlbumArt}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Height="100" Width="100" Margin="12,0,9,0" Source="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This way you will get the desired result. Read more about UniformGrid here: MSDN
The reason why your solution does not work, is that Listbox panel puts items one under another, whereas UniformGrid puts them from left to right, until there is available space or has hit the columns limit and then goes down the row.
You can use two StackPanels, one with verticle orientation and one with horizontal. Here's your code edited to include them:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Verticle">
<StackPanel Orientation="Horizontal">
<Image Height="100" Width="100" Margin="12,0,9,0" Source="{Binding AlbumArt}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>

Ungrouped Long List Selector

Okay, So I am trying to bind a list of objects with a DisplayName property to a long list selector.
XAML Code
<phone:LongListSelector x:Name="lls_TemplateFields" HorizontalAlignment="Left" Width="450" Grid.Row="2" Height="400" LayoutMode="List" Background="#FF9E9D9D" IsGroupingEnabled="False">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding DisplayName}" Foreground="Black" FontSize="24"/>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
C# Code
List<AttributeDefinition> m_SelectedAttributes = new List<AttributeDefinition>();
lls_TemplateFields.ItemsSource = m_SelectedAttributes;
My Class AttributeDefinition contains a property for DisplayName. If I group the the list using a group key then the list will show up, however I cannot get just a plain list of items to show up. Like a listbox in WPF C#.
I am using this list to represent a list of chosen AttributeDefinitions from another list that shows all the AttributeDefinitions grouped alphabetically by their DisplayName property, and the Display Value is Binded to the DisplayName Property like shown below...
XAML
<phone:LongListSelector x:Name="lls_AttributeList" HorizontalAlignment="Left" Height="450" VerticalAlignment="Top" Width="450" HideEmptyGroups="True" IsGroupingEnabled="True" SelectionChanged="SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderThickness="2">
<TextBlock Text="{Binding DisplayName}" Foreground="{StaticResource PhoneChromeBrush}" FontSize="24"/>
</Border>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
<phone:LongListSelector.GroupHeaderTemplate>
<DataTemplate>
<Grid Width="50" Height="50" HorizontalAlignment="Left" VerticalAlignment="Center" Background="Blue">
<Border BorderThickness="4">
<TextBlock Text="{Binding Key}" Foreground="White" FontSize="38" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</Grid>
</DataTemplate>
</phone:LongListSelector.GroupHeaderTemplate>
</phone:LongListSelector>
C#
List<AttributeKeyGroup<AttributeDefinition>> DataSource = AttributeKeyGroup<AttributeDefinition>.CreateGroups(AttributeData,
Thread.CurrentThread.CurrentUICulture,
(AttributeDefinition aDef) => { return aDef.Type; },
true);
lls_AttributeList.ItemsSource = DataSource;
This list works just fine. And the data in the background is functioning properly, because as I select items from the total list of attributedefinitions they are removed from the LongListSelector and added to the LongListSelector of the selected lists Itemssource
For further inquiry into more code surrounding this User Control please feel free to ask I will disclose as much code as I can without breaking my non-disclosure agreement with my work. Thank you for taking the time to read and possibly help. Much appreciated.
List<AttributeDefinition> m_SelectedAttributes = new List<AttributeDefinition>();
lls_TemplateFields.ItemsSource = m_SelectedAttributes;
because you just instantiated this list and binding it right away? How about adding some items into the list
There are two answers to this. I have tried both and both work.
[1] You have to set the LongListSelector.ScrollTo(object) to the first object of your list when you update the data if the list has 1 or more items. Such as...
lls_TemplateFields.ItemsSource = m_SelectedAttributes;
if(m_SelectedAttributes.Count > 0)
{
lls_TemplateFields.ScrollTo(m_SelectedAttributes[0]);
}
[2] The proper way to fix this is to use ObservableCollections which work better with DataBinding and the WP8 WPF SDK UI to update on adding objects to the ObservableCollection.
ObservableCollection<AttributeDefinition> m_SelectedAttributes =
new ObservableCollection<AttributeDefinition>();
lls_TemplateFields.ItemsSource = m_SelectedAttributes

Accessing group-headings sub elements in data-bound GridView

I'm developing a windows 8 metro application with a data-bound gridview xaml control.
I've added a ring progress bar named progressRingGroup to header of the groups as seen below.
<ProgressRing x:Name="progressRingGroup" IsActive="True" Visibility="Visible" Width="16" Height="16" Margin="0,-7,0,0"/>
I want to programmatically access the ring-progress-bar from my code (so I can start/stop it) but as my grid-view is databound I don't know how to do so.
I've multiple groups in the gridview and need to access all of them separately.
Here's my gridview's groupstyle xaml definition;
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="1,0,0,6">
<Button
AutomationProperties.Name="Group Title"
Click="Header_Click"
Style="{StaticResource TextPrimaryButtonStyle}" >
<StackPanel Orientation="Horizontal">
<ProgressRing x:Name="progressRingGroup" IsActive="True" Visibility="Visible" Width="16" Height="16" Margin="0,-7,0,0"/>
<TextBlock Text="{Binding Title}" Margin="6,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />
<TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-7,0,10" Style="{StaticResource GroupHeaderTextStyle}"/>
</StackPanel>
</Button>
</Grid>
</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>
Help appreciated.
If you want to be able to control the IsActive property of each progress ring, add a bool property to your group data model, and bind IsActive to that property. That way you can control each ProgressRing without having to programatically access all of them.
For example:
<ProgressRing x:Name="progressRingGroup" IsActive="{Binding GroupLoading}" Visibility="Visible" Width="16" Height="16" Margin="0,-7,0,0"/>
If you still want to access each programmatically, you could assign a Loaded event to the ProgressRing in the DataTemplate, and when the event fires, grab a reference to the ring (sender).

XAML grouped GridView/Semantic Zoom not displaying all children?

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>

Categories

Resources