.NET MAUI How to make a proper Gridlayout in Collectionview with Header? - c#

I'm trying to build a table in .NET MAUI based on a Grid Layout. This is the code:
<CollectionView ItemsSource="{Binding digitalInputs}">
<CollectionView.Header>
<Grid ColumnDefinitions="*,*,*,*">
<Label Text="Name" Grid.Column="0"/>
<Label Text="Typ" Grid.Column="1"/>
<Label Text="Status" Grid.Column="2"/>
<Label Text="Aktiv" Grid.Column="3"/>
</Grid>
</CollectionView.Header>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="services:DigitalInput">
<Grid ColumnDefinitions="*,*,*,*">
<Label Text="{Binding pName}" Grid.Column="0"/>
<Label Text="{Binding pDigitalType}" Grid.Column="1"/>
<Label Text="{Binding pValueText}" Grid.Column="2"/>
<Label Text="{Binding pActive}" Grid.Column="3"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
This is the result when running in Debug Mode on MacCatalyst (Visual Studio for Mac):
Now I wonder how I can align the header grid properly to the grid in the data template? Does someone have a suggestion on how I can improve the code to build a proper table?
Edit: This seems to be a bug in the IDE. When I change the HorizontalOptions property on the Grid in the CollectionView.Header, as a comment suggested, the XAML Hot-Reload triggers a re-rendering of the view and all of a sudden the header grid aligns correctly with the grid in the ItemTemplate.

I tested the code you provided in iOS, Windows in MAUI. And it can align the header grid properly to the grid in the data template in CollectionView. So the issue could be related with the services:DigitalInput retrieving the data, they should be correctly formatted with no blank space in those properties.
Below are the code sample and running output, hope it can shed some light for you!
XAML:
<CollectionView ItemsSource="{Binding digitalInputs}">
<CollectionView.Header>
<Grid ColumnDefinitions="*,*,*,*">
<Label Text="Name" Grid.Column="0"/>
<Label Text="Typ" Grid.Column="1"/>
<Label Text="Status" Grid.Column="2"/>
<Label Text="Aktiv" Grid.Column="3"/>
</Grid>
</CollectionView.Header>
<CollectionView.ItemTemplate>
<DataTemplate >
<Grid ColumnDefinitions="*,*,*,*">
<Label Text="{Binding pName}" Grid.Column="0"/>
<Label Text="{Binding pDigitalType}" Grid.Column="1"/>
<Label Text="{Binding pValueText}" Grid.Column="2"/>
<Label Text="{Binding pActive}" Grid.Column="3"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Code-behind:
public ObservableCollection<Model> digitalInputs { get; set; }
public NewPage1()
      {
            InitializeComponent();
            //assign data
            digitalInputs = new ObservableCollection<Model>()
            {
                  new Model{pName="KipSchalter", pDigitalType="Zustand",pActive="OFF", pValueText="True" },
new Model{pName="KipSchalter", pDigitalType="Zustand",pActive="OFF", pValueText="True" },
new Model{pName="Digital In 3", pDigitalType="Zustand",pActive="OFF", pValueText="FALSE" },
new Model{pName="Digital In 4", pDigitalType="Zustand",pActive="OFF", pValueText="FALSE" }
}
            ;
            BindingContext = this;
      }
iOS output:
Windows output:
Update:
This seems to be a potential issue in the IDE. When changing the HorizontalOptions property on the Grid as Jason suggested, the header grid aligns correctly with the grid in the ItemTemplate.

If you mean by arranging children horizontally first and then pushing down to the next row then the current MAUI still does not support that, you can only trigger span (also span isn't changing at runtime on WinUI right now, I think the team is fixing it) or create a custom one
public class HorizontalWrapLayout : StackLayout
{
public HorizontalWrapLayout()
{
}
protected override ILayoutManager CreateLayoutManager()
{
return new HorizontalWrapLayoutManager(this);
}
}
public class HorizontalWrapLayoutManager : StackLayoutManager
{
HorizontalWrapLayout _layout;
public HorizontalWrapLayoutManager(HorizontalWrapLayout horizontalWrapLayout) : base(horizontalWrapLayout)
{
_layout = horizontalWrapLayout;
}
public override Size Measure(double widthConstraint, double heightConstraint)
{
var padding = _layout.Padding;
widthConstraint -= padding.HorizontalThickness;
var rows = new Dictionary<int, List<Size>>();
var currentRowIndex = 0;
var currentRow = new List<Size>();
rows.Add(currentRowIndex, currentRow);
foreach (var child in _layout)
{
if (child.Visibility == Visibility.Collapsed)
{
continue;
}
var childSize = child.Measure(double.PositiveInfinity, heightConstraint);
var childWidth = childSize.Width + (currentRow.Any() ? _layout.Spacing : 0);
var rowWidth = currentRow.Aggregate(0.0, (w, x) => w + x.Width);
if (rowWidth + childWidth > widthConstraint)
{
if (currentRow.Any())
{
currentRowIndex++;
currentRow = new List<Size>();
rows.Add(currentRowIndex, currentRow);
}
}
else if (currentRow.Any())
{
currentRow.Add(new Size(_layout.Spacing, 0));
}
currentRow.Add(childSize);
}
var totalWidth = 0.0;
var totalHeight = 0.0;
if (rows.Any())
{
var rowWidths = rows.Select(x => x.Value.Aggregate(0.0, (result, item) => result + item.Width)).ToList();
var rowHeights = rows.Select(x => x.Value.Any() ? x.Value.Max(i => i.Height) : 0).ToList();
totalWidth = rowWidths.Any() ? rowWidths.Max() : 0;
totalHeight = rowHeights.Any() ? rowHeights.Sum() : 0;
if (rows.Keys.Count > 1)
{
totalHeight += _layout.Spacing * (rows.Keys.Count - 1);
}
}
totalWidth += padding.HorizontalThickness;
totalHeight += padding.VerticalThickness;
var finalHeight = ResolveConstraints(heightConstraint, Stack.Height, totalHeight, Stack.MinimumHeight, Stack.MaximumHeight);
var finalWidth = ResolveConstraints(widthConstraint, Stack.Width, totalWidth, Stack.MinimumWidth, Stack.MaximumWidth);
return new Size(finalWidth, finalHeight);
}
public override Size ArrangeChildren(Rect bounds)
{
var padding = Stack.Padding;
double top = padding.Top + bounds.Top;
double left = padding.Left + bounds.Left;
double currentRowTop = top;
double currentX = left;
double currentRowHeight = 0;
double maxStackWidth = currentX;
for (int n = 0; n < _layout.Count; n++)
{
var child = _layout[n];
if (child.Visibility == Visibility.Collapsed)
{
continue;
}
if (currentX + child.DesiredSize.Width > bounds.Right)
{
// Keep track of our maximum width so far
maxStackWidth = Math.Max(maxStackWidth, currentX);
// Move down to the next row
currentX = left;
currentRowTop += currentRowHeight + _layout.Spacing;
currentRowHeight = 0;
}
var destination = new Rect(currentX, currentRowTop, child.DesiredSize.Width, child.DesiredSize.Height);
child.Arrange(destination);
currentX += destination.Width + _layout.Spacing;
currentRowHeight = Math.Max(currentRowHeight, destination.Height);
}
var actual = new Size(maxStackWidth, currentRowTop + currentRowHeight);
return actual.AdjustForFill(bounds, Stack);
}
Usage
<app:HorizontalWrapLayout
BindableLayout.ItemTemplate="{x:StaticResource HorizontalWrapLayoutItemTemplate}"
BindableLayout.ItemsSource="{Binding ControlGroups, Mode=OneWay}"
HorizontalOptions="Center"
Spacing="50"
VerticalOptions="Center" />

Related

Xamarin Forms ListView, When TranslateTo Animation Hide By other Items

I intended to coding" when Listview items appearing and Items appearing " items appearing from top or bottom. ( using TranslateTo )
but When Listview Viewcell Appearing, or itemsAppearing, i tried to Apply animations.
but, higher index of items hiding lower index of items animation.
so, lower index items animation is only show shortly. ( cropped by other layout)
Please Check Image Description _ Animation Cropped by items
in Xamarin Forms(C#)
private async void ItemsListView_ItemAppearing_1(object sender, ItemVisibilityEventArgs e)
{
int i = e.ItemIndex;
int y;
y = 400;
for (int d = 0; d < i; d++)
{
int z = d + 1;
y = y + (400 / (z * z));
}
uint x = uint.Parse(y.ToString());
IEnumerable<PropertyInfo> pInfos = (ItemsListView as ItemsView<Cell>).GetType().GetRuntimeProperties();
var templatedItems = pInfos.FirstOrDefault(info => info.Name == "TemplatedItems");
if (templatedItems != null)
{
var cells = templatedItems.GetValue(ItemsListView);
var cell = (cells as Xamarin.Forms.ITemplatedItemsList<Xamarin.Forms.Cell>)[e.ItemIndex] as ViewCell;
//cell.View.Opacity = 0;
cell.View.TranslationY = Var.Device_Height / Var.Device_Scale;
await cell.View.TranslateTo(0, 0, x, Easing.CubicOut);
}
}
In XAML
<ListView x:Name="ItemsListView" BackgroundColor="Transparent" VerticalOptions="Fill" ItemsSource="{Binding Items}" Margin="0" SeparatorVisibility="None" RefreshCommand="{Binding LoadItemsCommand}"
IsPullToRefreshEnabled="True" HasUnevenRows="True" IsRefreshing="{Binding IsBusy, Mode=OneWay}" ItemAppearing="ItemsListView_ItemAppearing_1"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Appearing="ViewCell_Appearing">
<ViewCell.View>
<Frame IsClippedToBounds="False"
Margin="0,5"
CornerRadius="10"
Padding="0"
HasShadow="False"
BorderColor="#f0f0f0"
BackgroundColor="Transparent" >
<StackLayout Padding="0" Spacing="0" MinimumHeightRequest="0">
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Name}" Margin="13,12,5,0" FontAttributes="Bold" FontSize="18" TextColor="#222222">
</Label>
<Frame MinimumHeightRequest="0" VerticalOptions="EndAndExpand" Padding="7,2,7,2" CornerRadius="100" BackgroundColor="Accent" HasShadow="False">
<Label Text="{Binding Sequence}" TextColor="White" FontSize="Micro"/>
</Frame>
</StackLayout>
<Label Text="{Binding Mail}" Margin="13,6,0,12">
</Label>
</StackLayout>
</Frame>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
it is same result, when ViewCell_appearing or items_Appearing
Here is my background code for TranslateTo Animation Hide By other Items.
public static double Device_Height = DeviceDisplay.MainDisplayInfo.Height;
public static double Device_Scale = 6;
int i;
private async void mylistview_ItemAppearing(object sender, ItemVisibilityEventArgs e)
{
i = e.ItemIndex;
}
private async void ViewCell_Appearing(object sender, EventArgs e)
{
// int i = e.ItemIndex;
int y;
y = 4000;
for (int d = 0; d < i; d++)
{
int z = d + 1;
y = y + (400 / (z * z));
}
uint x = uint.Parse(y.ToString());
var cell = sender as ViewCell;
cell.View.TranslationY = Device_Height / Device_Scale;
await cell.View.TranslateTo(0, 0, x, Easing.CubicOut);
}
Here is running GIF(I slow down your animation).
I upload my demo to you, you can test it.
https://github.com/851265601/Xamarin.Android_ListviewSelect/blob/master/MyCusListview.zip
To reply on #Leon Lu :Yes there is a way.
You could check if the integer i == 0.
public static double Device_Height = DeviceDisplay.MainDisplayInfo.Height;
public static double Device_Scale = 6;
int i;
private async void mylistview_ItemAppearing(object sender, ItemVisibilityEventArgs e)
{
i = e.ItemIndex;
}
private async void ViewCell_Appearing(object sender, EventArgs e)
{
if(i == 0)
{
int y;
y = 4000;
for (int d = 0; d < i; d++)
{
int z = d + 1;
y = y + (400 / (z * z));
}
uint x = uint.Parse(y.ToString());
var cell = sender as ViewCell;
cell.View.TranslationY = Device_Height / Device_Scale;
await cell.View.TranslateTo(0, 0, x, Easing.CubicOut);
}
}
But unfortunally now it animates only the second row. But I'm looking for an solution!
I think, in my case, it has something to do with the ListView population through the Binding..

Binding points to chart from Interactive Data Display WPF library

I want plot oscilloscope -like dynamic line chart in WPF and I found this library: Interactive Data Display which emerged from this library: D3 Dynamic Data Display. The advantage is that its light which is important for me.
From sample program, I can see that they do not bind the LineGraph.Points with any collection, and when I tried that it did not work, there is also no Refresh or Update method on the Graph object. Currently, I'm forced to use LineGraph.PlotY() method every time I want to update my graph.
Does anyone know if it's possible to use this library in MVVM way?
Sample code:
double[] x = new double[200];
for (int i = 0; i < x.Length; i++)
x[i] = 3.1415 * i / (x.Length - 1);
for (int i = 0; i < 25; i++)
{
var lg = new LineGraph();
lines.Children.Add(lg);
lg.Stroke = new SolidColorBrush(Color.FromArgb(255, 0, (byte)(i * 10), 0));
lg.Description = String.Format("Data series {0}", i + 1);
lg.StrokeThickness = 2;
lg.Plot(x, x.Select(v => Math.Sin(v + i / 10.0)).ToArray());
}
XAML:
<d3:Chart Name="plotter">
<d3:Chart.Title>
<TextBlock HorizontalAlignment="Center" FontSize="18" Margin="0,5,0,5">Line graph legend sample</TextBlock>
</d3:Chart.Title>
<d3:Chart.LegendContent>
<d3:LegendItemsPanel>
<d3:LegendItemsPanel.Resources>
<DataTemplate x:Key="InteractiveDataDisplay.WPF.LineGraph">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=Visibility, Converter={StaticResource VisibilityToCheckedConverter}, Mode=TwoWay}"/>
<Line Width="15" Height="15" X1="0" Y1="0" X2="15" Y2="15" Stroke="{Binding Path=Stroke}" StrokeThickness="2"/>
<TextBlock Margin="5,0,0,0" Text="{Binding Path=Description}"/>
</StackPanel>
</DataTemplate>
</d3:LegendItemsPanel.Resources>
</d3:LegendItemsPanel>
</d3:Chart.LegendContent>
<Grid Name="lines"/>
</d3:Chart>
In the Plot base class, there is already a dependency property registered for the Pointsproperty. As a 'quick-fix', I added this to the LineGraphclass:
public ObservableCollection<Point> ObservablePoints
{
get { return (ObservableCollection<Point>)GetValue(ObservablePointsProperty); }
set { SetValue(ObservablePointsProperty, value); }
}
public static readonly DependencyProperty ObservablePointsProperty =
DependencyProperty.RegisterAttached(
"ObservablePoints",
typeof(ObservableCollection<Point>),
typeof(LineGraph),
new PropertyMetadata(
new ObservableCollection<Point>(),
(d, e) =>
{
var linePlot = (LineGraph)d;
var updateAction = new NotifyCollectionChangedEventHandler(
(o, args) =>
{
if (linePlot != null)
{
InteractiveDataDisplay.WPF.Plot.SetPoints(linePlot.polyline, new PointCollection((ObservableCollection<Point>)o));
}
});
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged)e.OldValue;
coll.CollectionChanged -= updateAction;
}
if (e.NewValue != null)
{
var coll = (INotifyCollectionChanged)e.NewValue;
coll.CollectionChanged += updateAction;
if (linePlot != null)
{
InteractiveDataDisplay.WPF.Plot.SetPoints(linePlot.polyline, new PointCollection((ObservableCollection<Point>)e.NewValue));
}
}
}));
Then, bound my collection of points to the ObservablePoints property:
<d3:LineGraph Description="MyGraph"
ObservablePoints="{Binding Path=PointsFromMyDatamodel}"/>
The drawback is that the graph for all points is redrawn - thus the 'quick-fix'. Redrawing only added, modified or removed points would require more changes to underlying base classes...

How can I make the images I gather into a "instagram" listview?

Right now when I gather my data (the images) I get 3 of the same image in the same row. I want the image to gather inside my listview by laying next to eachother (3 unique images on each row) and then move down a row.
This is my current code:
new List<info> imagesList = new List<info> ();
protected override void OnAppearing()
{
imagesListview.RowHeight = (int)(this.Width / 3);
}
async void loadPhotos ()
{
var getInfo = await phpApi.getPhotos ();
imagesListview.ItemsSource = null;
imagesList = new List<info> ();
foreach (var items in getInfo["results"]) {
imagesList.Add (new info () {
theimage = items ["Photo"].ToString(),
theimage2 = items ["Photo"].ToString(),
theimage3 = items ["Photo"].ToString(),
});
}
imagesListview.ItemsSource = imagesList;
}
public class info
{
public string theimage {get; set;}
public string theimage2 {get; set;}
public string theimage3 {get; set;}
}
XAML:
<ListView x:Name="imagesListview" RowHeight="100" AbsoluteLayout.LayoutBounds="0.0, 1.0, 1.0, 0.75" AbsoluteLayout.LayoutFlags="All">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<AbsoluteLayout>
<Image Source="{Binding theimage}" AbsoluteLayout.LayoutBounds="0.0, 0.0, 0.333, 1.0" AbsoluteLayout.LayoutFlags="All" Aspect = "AspectFill" />
<Image Source="{Binding theimage2}" AbsoluteLayout.LayoutBounds="0.5, 0.0, 0.333, 1.0" AbsoluteLayout.LayoutFlags="All" Aspect = "AspectFill" />
<Image Source="{Binding theimage3}" AbsoluteLayout.LayoutBounds="1.0, 0.0, 0.333, 1.0" AbsoluteLayout.LayoutFlags="All" Aspect = "AspectFill" />
</AbsoluteLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
int ndx = 0;
Info info = null;
foreach (var items in getInfo["results"]) {
if (ndx == 0) {
info = new Info();
info.theimage = items ["Photo"].ToString();
ndx++;
} else
if (ndx == 1) {
info.theimage2 = items ["Photo"].ToString();
ndx++;
} else
if (ndx == 2) {
info.theimage3 = items ["Photo"].ToString();
imagesList.Add(info);
info = null;
ndx = 0;
}
}
if (info != null) {
imagesList.Add(info);
}

Create a dynamic grid view with varying cell size in C#

I want to create a grid view with varying cell size. But due to the inbuilt windows feature in which the cells adjust themselves in the row, I get the following result.
But I want to get a grid with a feature similar to staggered grid in android as given in this link:
https://dzone.com/articles/how-implement-staggered-grid
Is there a method to do this in WP8.1 programming?
In xaml Use ItemsControl that Represents a control that can be used to present a collection of items.
Create a new Panel that we can use for any ItemsControl. for more information refer this link: http://www.visuallylocated.com/post/2015/02/20/Creating-a-WrapPanel-for-your-Windows-Runtime-apps.aspx
write a class in xaml.cs as follows.
public class WrapPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
// Just take up all of the width
Size finalSize = new Size { Width = availableSize.Width };
double x = 0;
double rowHeight = 0d;
foreach (var child in Children)
{
// Tell the child control to determine the size needed
child.Measure(availableSize);
x += child.DesiredSize.Width;
if (x > availableSize.Width)
{
// this item will start the next row
x = child.DesiredSize.Width;
// adjust the height of the panel
finalSize.Height += rowHeight;
rowHeight = child.DesiredSize.Height;
}
else
{
// Get the tallest item
rowHeight = Math.Max(child.DesiredSize.Height, rowHeight);
}
}
// Just in case we only had one row
if (finalSize.Height == 0)
{
finalSize.Height = rowHeight;
}
return finalSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
Rect finalRect = new Rect(0, 0, (finalSize.Width / 2) - 10, finalSize.Height);
double EvenItemHeight = 0;
double OddItemHeight = 0;
int itemNumber = 1;
foreach (var child in Children)
{
if (itemNumber % 2 == 0)
{
finalRect.X = (finalSize.Width / 2);
finalRect.Y = EvenItemHeight;
EvenItemHeight += Children[itemNumber - 1].DesiredSize.Height;
}
else
{
finalRect.X = 0;
finalRect.Y = OddItemHeight;
OddItemHeight += Children[itemNumber - 1].DesiredSize.Height;
}
itemNumber++;
child.Arrange(finalRect);
}
return finalSize;
}
}
StaggerGrid.xaml code is as follows:
xmlns:local="using:StaggerGridSample.Views"// namespace of class WrapPanel
<Grid>
<ScrollViewer >
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding StrList,UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Background="Red"
Width="185"
VerticalAlignment="Top"
Margin="0,0,6,0">
<TextBlock Text="{Binding}"
VerticalAlignment="Top"
TextWrapping="Wrap"
FontSize="20"/>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>

Alphabetically searching of records via accessing rest services in windows phone 7

I am trying to make Alphabetically searching of records via accessing rest services in windows phone 7.
Design page code..
<controls:PivotItem Header="buddies">
<toolkit:LongListSelector x:Name="BookList" Background="Transparent" IsFlatList="true"
GroupViewOpened="LongListSelector_GroupViewOpened"
GroupViewClosing="LongListSelector_GroupViewClosing">
<toolkit:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</toolkit:LongListSelector.GroupItemsPanel>
<toolkit:LongListSelector.GroupItemTemplate>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource GroupBackground}}"
Width="99" Height="99" Margin="6" IsHitTestVisible="{Binding HasItems}">
<TextBlock Text="{Binding Title}"
FontFamily="{StaticResource PhoneFontFamilySemiBold}"
FontSize="48"
Margin="8,0,0,0"
Foreground="{Binding Converter={StaticResource GroupForeground}}"
VerticalAlignment="Bottom"/>
<Border.Projection>
<PlaneProjection RotationX="-60"/>
</Border.Projection>
</Border>
</DataTemplate>
</toolkit:LongListSelector.GroupItemTemplate>
<toolkit:LongListSelector.GroupHeaderTemplate>
<DataTemplate>
<Border Background="Transparent" Margin="12,8,0,8">
<Border Background="{StaticResource PhoneAccentBrush}"
Padding="8,0,0,0" Width="62" Height="62"
HorizontalAlignment="Left">
<TextBlock Text="{Binding Title}"
Foreground="#FFFFFF"
FontSize="48"
FontFamily="{StaticResource PhoneFontFamilySemiLight}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"/>
</Border>
</Border>
</DataTemplate>
</toolkit:LongListSelector.GroupHeaderTemplate>
<toolkit:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid Margin="12,8,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Width="110" Height="150" Source="{Binding ImageUrl}" VerticalAlignment="Top"/>
<StackPanel Grid.Column="1" VerticalAlignment="Top">
<TextBlock Text="{Binding AutherName}" Style="{StaticResource PhoneTextLargeStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" Margin="12,-12,12,6"/>
<TextBlock Text="{Binding Email}" Style="{StaticResource PhoneTextNormalStyle}" TextWrapping="Wrap" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Title:" Style="{StaticResource PhoneTextSmallStyle}"/>
<TextBlock Text="{Binding Title}" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Price:" Style="{StaticResource PhoneTextSmallStyle}"/>
<TextBlock Text="{Binding Price}" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</toolkit:LongListSelector.ItemTemplate>
</toolkit:LongListSelector>
</controls:PivotItem>
</controls:Pivot>
</Grid>
Here is my MainPage.xaml.cs page code
private LongListSelector currentSelector;
List<Person> objperson = null;
// Constructor
public MainPage()
{
InitializeComponent();
string Categoryid = "2";
WebClient proxy = new WebClient();
proxy.DownloadStringAsync(new Uri("http://localhost:3160/Service1.svc/GetListItemDetail/" + Categoryid));
proxy.DownloadStringCompleted += new DownloadStringCompletedEventHandler(proxy_DownloadStringCompleted);
}
void proxy_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
XDocument doc = XDocument.Load(new StringReader(e.Result));
var CatList = (from item in doc.Descendants("ItemDetail")
select new Person
{
GenreName = item.Element("GenreName").Value.ToString(),
ItemID = Convert.ToInt32(item.Element("ItemID").Value),
CatID = Convert.ToInt32(item.Element("CatID").Value),
GenreID = Convert.ToInt32(item.Element("GenreID").Value),
AutherName = item.Element("AutherName").Value.ToString(),
Title = item.Element("Title").Value.ToString(),
Email = item.Element("Email").Value.ToString(),
Price = item.Element("Price").Value.ToString(),
Description = item.Element("Description").Value.ToString(),
ImageUrl = item.Element("ImageUrl").Value.ToString()
}).ToList();
objperson = new List<Person>();
objperson = CatList;
BookList.ItemsSource = CatList;
}
}
public List<Person> GetPersonListInfo()
{
List<Person> objp = new List<Person>();
objp = objperson;
return objp;
}
private void LongListSelector_GroupViewOpened(object sender, GroupViewOpenedEventArgs e)
{
//Hold a reference to the active long list selector.
currentSelector = sender as LongListSelector;
//Construct and begin a swivel animation to pop in the group view.
IEasingFunction quadraticEase = new QuadraticEase { EasingMode = EasingMode.EaseOut };
Storyboard _swivelShow = new Storyboard();
ItemsControl groupItems = e.ItemsControl;
foreach (var item in groupItems.Items)
{
UIElement container = groupItems.ItemContainerGenerator.ContainerFromItem(item) as UIElement;
if (container != null)
{
Border content = VisualTreeHelper.GetChild(container, 0) as Border;
if (content != null)
{
DoubleAnimationUsingKeyFrames showAnimation = new DoubleAnimationUsingKeyFrames();
EasingDoubleKeyFrame showKeyFrame1 = new EasingDoubleKeyFrame();
showKeyFrame1.KeyTime = TimeSpan.FromMilliseconds(0);
showKeyFrame1.Value = -60;
showKeyFrame1.EasingFunction = quadraticEase;
EasingDoubleKeyFrame showKeyFrame2 = new EasingDoubleKeyFrame();
showKeyFrame2.KeyTime = TimeSpan.FromMilliseconds(85);
showKeyFrame2.Value = 0;
showKeyFrame2.EasingFunction = quadraticEase;
showAnimation.KeyFrames.Add(showKeyFrame1);
showAnimation.KeyFrames.Add(showKeyFrame2);
Storyboard.SetTargetProperty(showAnimation, new PropertyPath(PlaneProjection.RotationXProperty));
Storyboard.SetTarget(showAnimation, content.Projection);
_swivelShow.Children.Add(showAnimation);
}
}
}
_swivelShow.Begin();
}
private void LongListSelector_GroupViewClosing(object sender, GroupViewClosingEventArgs e)
{
//Cancelling automatic closing and scrolling to do it manually.
e.Cancel = true;
if (e.SelectedGroup != null)
{
currentSelector.ScrollToGroup(e.SelectedGroup);
}
//Dispatch the swivel animation for performance on the UI thread.
Dispatcher.BeginInvoke(() =>
{
//Construct and begin a swivel animation to pop out the group view.
IEasingFunction quadraticEase = new QuadraticEase { EasingMode = EasingMode.EaseOut };
Storyboard _swivelHide = new Storyboard();
ItemsControl groupItems = e.ItemsControl;
foreach (var item in groupItems.Items)
{
UIElement container = groupItems.ItemContainerGenerator.ContainerFromItem(item) as UIElement;
if (container != null)
{
Border content = VisualTreeHelper.GetChild(container, 0) as Border;
if (content != null)
{
DoubleAnimationUsingKeyFrames showAnimation = new DoubleAnimationUsingKeyFrames();
EasingDoubleKeyFrame showKeyFrame1 = new EasingDoubleKeyFrame();
showKeyFrame1.KeyTime = TimeSpan.FromMilliseconds(0);
showKeyFrame1.Value = 0;
showKeyFrame1.EasingFunction = quadraticEase;
EasingDoubleKeyFrame showKeyFrame2 = new EasingDoubleKeyFrame();
showKeyFrame2.KeyTime = TimeSpan.FromMilliseconds(125);
showKeyFrame2.Value = 90;
showKeyFrame2.EasingFunction = quadraticEase;
showAnimation.KeyFrames.Add(showKeyFrame1);
showAnimation.KeyFrames.Add(showKeyFrame2);
Storyboard.SetTargetProperty(showAnimation, new PropertyPath(PlaneProjection.RotationXProperty));
Storyboard.SetTarget(showAnimation, content.Projection);
_swivelHide.Children.Add(showAnimation);
}
}
}
_swivelHide.Completed += _swivelHide_Completed;
_swivelHide.Begin();
});
}
private void _swivelHide_Completed(object sender, EventArgs e)
{
//Close group view.
if (currentSelector != null)
{
currentSelector.CloseGroupView();
currentSelector = null;
}
}
I am new to windows phone 7 application development, no idea about grouping of alphabets in Longlistselector. Please help me in that. Thanks in advance.
There is code I used once for grouping. As you can see, it's similar to Claus's:
public class YourList : ObservableCollection<ItemsInGroup>
{
private static readonly string Groups = "#abcdefghijklmnopqrstuvwxyz";
Dictionary<string, ItemsInGroup> groups = new Dictionary<string, ItemsInGroup>();
public YourList()
{
foreach (char c in Groups)
{
ItemsInGroup group = new ItemsInGroup(c.ToString());
this.Add(group);
groups[c.ToString()] = group;
}
}
public void AddItem(Item item)
{
string GroupKey = Item.GetSomeFieldKey(item);// a, b, etc.
for (int i = 0; i < groups[GroupKey].Count; i++)
{
if (Item.CompareBySomeField(item, groups[GroupKey][i]) < 0)
{
groups[Item.GetSomeFilesKey(item)].Insert(i, item);
return;
}
}
groups[GroupKey].Add(item);
}
}
.
public class ItemsInGroup : ObservableCollection<Item>, INotifyPropertyChanged
{
public ItemsInGroup(string category)
{
Key = category;
}
public string Key { get; set; }
public bool HasItems { get { return Count > 0; } }
//INotifyPropertyChanged implementation
}
Item must implement:
public static string GetSomeFieldKey(Item item)
and
public static int CompareBySomeFields(object obj1, object obj2)
Usage:
YourList list = new YourList();
foreach (var item in resultListFromService)
{
list.AddItem(item); // fill list with items
}
myList.ItemsSource = list; // bind to UI
Hope this helps better understand how it works
A super easy way to do it, is to use a specialized collection for the LongListSelector. I just so happen to have written one
Basically you would change your code to the following:
BookList.ItemsSource = new LongListCollection<Person, char>(CatList, x => x.Title[0]));
And you would get the alphabetic grouping on the first character of the Title property.
The only detail you need to be aware of, is that your Person class would need to implement IComparable<Person> to be ordered by the Title property (because you do want sorting, right?)
Simply done as:
public int Compare(Person other)
{
if (other == null)
return 1;
return this.Title.CompareTo(other.Title);
}

Categories