Reuse Dynamically created view [duplicate] - c#

This question already has an answer here:
Reusing Text views and Grid
(1 answer)
Closed 8 years ago.
I am dynamically creating say 300 views in For loop :
Ex:
for (int j = 0; j <= 300; j++)
{
Image image = new Image();
image.Source = new BitmapImage(new Uri("/Images/sample256.png", UriKind.RelativeOrAbsolute));
Grid titleGrid = new Grid();
titleGrid.HorizontalAlignment = HorizontalAlignment.Center;
titleGrid.VerticalAlignment = VerticalAlignment.Center;
TextBlock titleText = new TextBlock();
titleText.TextWrapping = TextWrapping.Wrap;
titleGrid.Children.Add(titleText);
Grid subtitleGrid = new Grid();
subtitleGrid.HorizontalAlignment = HorizontalAlignment.Center;
subtitleGrid.VerticalAlignment = VerticalAlignment.Center;
TextBlock subtitleText = new TextBlock();
subtitleText.TextWrapping = TextWrapping.Wrap;
subtitleGrid.Children.Add(subtitleText);
//add all views to root layout
LayoutRoot.Children.Add(image);
LayoutRoot.Children.Add(titleGrid);
LayoutRoot.Children.Add(subtitleGrid);
}
Now there is a lag in the app as I am adding new view each time, how can I reuse the already created views? I am working on Windows Phone 8 app.

adding 300 items in the layout root will definatly make page load slow. you need to use controls that implement virtulization like listbox. here is how
ListBox XAML in your page.
<ListBox Name="myListBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding ImageUrl}">
</Image>
<TextBlock Text="{Binding Question}"></TextBlock>
<TextBlock Text="{Binding Answer}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
your code behind
code to bind data
List<MyData> list = new List<MyData>();
for (int i = 0; i < 300; i++)
{
var data = new MyData();
data.Question = "//yourquestion";
data.Answer = "// your answer";
data.ImageSource = new BitmapImage(new Uri("yourimagepat"));
}
myListBox.ItemsSource = list;
Data Class
public class MyData {
public string Question { get; set; }
public string Answer { get; set; }
public BitmapImage ImageSource { get; set; }
}
to take advantage of the virtulization please add your listbox in Grid control. otherwise it can throw out of memory exception and also will be slow

You could try using DataBinding feature instead of creating this .
// You can bound items from your Class here
<ListBox x:Name="ListBox1" Margin="5"
Width="450" Height="200" HorizontalAlignment="Left"
ItemsSource="{Binding SongsList}">
ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel CleanUpVirtualizedItemEvent="VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1">
</VirtualizingStackPanel>
</ItemsPanelTemplate>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="2">
<TextBlock Text="Artist:" Margin="2" />
<TextBlock Text="{Binding Artist}" Margin="2" />
<TextBlock Text="CD:" Margin="10,2,0,2" />
<TextBlock Text="{Binding Name}" Margin="2" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
// your class should be like this
public Songs
{
public string Artist{get;set;}
public string Name {get;set;}
}
// CodeBehind Just Add Data
ObservableCollection<Songs> SongsList=new ObservableCollection<SongsL();
for (int j = 0; j <= 300; j++)
{
SongsList.Add(new Songs{Artist="Aritst Name",Name="Song Name"});
}
// Set this Collection from the codebehind or xaml .
ListBox1.ItemSource=SongsList; // it will the bind the public properties in this Songs.
DataBinding Controls on Windows phone
Msdn Databindin greference
Binding data Grid
Databinding from Jesse Liberty

Related

Windows Wpf how can I dynamically create xaml grid using c#

Using Visual Studio 2019 + Resharper.
hey guys, i want to add listviews, that show things from objects, which i get from a list.
it looks like this, when i code it manually:
The XAML-Code:
<ListView Margin="43,313,642,29" BorderThickness="2" BorderBrush="Red" x:Name="Module1">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="Modul"/>
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and the c# code:
List<Module> somename = pPP_2.Components.Modules.Values.Cast<Module>().ToList();
List<Module> whatevername = new List<Module>(){somename[0]};
Module1.ItemsSource = whatevername;
The Modules i refer to have several properties, and the {somename[0]} just gets the first of them and puts it in the list.
So basically my question:
How can i create such xaml code using c#? I want to create a listview like this for each element in my list. i DonĀ“t want to create them manually but let the code do it for me.
thinking about this for days now and would love to get some help here.
Thanks,
IRezzet.
P.S. You can basically ignore the special list i created there. The question should work for every List.
You could use an ItemsControl with a ItemTemplate that renders a ListView that has an ItemTemplate rendering the listview-items. If this gets too complex, consider seperating this into a usercontrol to make it more generic.
The XAML would look something like this:
<ItemsControl x:Name="DynamicGrid">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListView BorderThickness="2" ItemsSource="{Binding SubChildren}" BorderBrush="Red">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You will need two Model types for this
// And an instance variable
public ObservableCollection<Outer> Lists { get; } = new ObservableCollection<Outer>();
public class Outer
{
public ObservableCollection<Inner> SubChildren { get; } = new ObservableCollection<Inner>();
}
public class Inner
{
public string Name { get; set; }
}
I used this code to seed for testing:
for (int i = 0; i < 10; i++)
{
var o = new Outer();
for (int k = 0; k < 10; k++)
{
o.SubChildren.Add(new Inner() { Name = "ID: "+k });
}
Lists.Add(o);
}
DynamicGrid.ItemsSource = Lists;

Filter List view on item click - uwp

I have a list view which shows main subject and optional subject of students selected. Now I want to filter the listview when clicking on each row of it. The filtering should be based on main subject and optional subject. Means filtered rows of listview either contains any of main subject or optional subject.
<ListView x:Name="ItemListView" Width="Auto" Height="Auto" HorizontalAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding StudentName}" TextAlignment="Left" FontSize="20" Width="50"/>
</StackPanel>
<StackPanel>
<TextBlock Text="{Binding MainSub}" FontSize="20" TextAlignment="Center" />
</StackPanel>
<StackPanel>
<TextBlock Text="{Binding OptionalSub}" FontSize="20" TextAlignment="Center" />
</StackPanel>
<StackPanel >
<TextBlock Text="{Binding RollNo}" FontSize="20" TextAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
ItemDetails messageData = new ItemDetails();
ItemListView.ItemsSource = messageData.Collection;
ItemListView.SelectedIndex = 0;
}
public class ItemDetails
{
public ItemDetails()
{
MatchList item;
item = new MatchList();
item.StudentName = "FF";
item.MainSub= selectedSub[0].ToString();//English
item.OptionalSub =selectedSub[1].ToString();//Sanskrit
item.RollNo = 922;
Collection.Add(item);
item = new MatchList();
item.StudentName = "DD";
item.MainSub= selectedSub[0].ToString();//English
item.OptionalSub =selectedSub[2].ToString();//Arabic
item.RollNo = 82;
Collection.Add(item);
item = new MatchList();
item.StudentName = "CC";
item.MainSub= selectedSub[3].ToString();//Science
item.OptionalSub =selectedSub[2].ToString();//Arabic
item.RollNo = 12;
Collection.Add(item);
item = new MatchList();
item.StudentName = "BB";
item.MainSub= selectedSub[3].ToString();//Science
item.OptionalSub =selectedSub[4].ToString();//Moral Science
item.RollNo = 22;
Collection.Add(item);
item = new MatchList();
item.StudentName = "AA";
item.MainSub= selectedSub[0].ToString();//English
item.OptionalSub =selectedSub[1].ToString();//Sanskrit
item.RollNo = 322;
Collection.Add(item);
}
List<MatchList> collection = new List<MatchList>();
public List<MatchList> Collection
{
get
{
return this.collection;
}
}
}
Well it seems several things are not yet complete in this sample code...
First up I suggest you use an ObservableCollection for the actual Collection property - this is needed so that your View will be notified if elements are added or removed from the collection.
Secondly you'll want to hook up a CollectionViewSource to your ListView ItemsSource and set it's Source to the ObservableCollection Collection property.
Last thing to do is then react to the ItemSelected of the ListView to filter out elements from the ObservableCollection. It should be reflected back to the ListView thanks to Data Binding.

Binding data in listview itemtemplate using style

I cannot bind my sample data to textblocks in stackpanel, which I defined in resources. I think that I use style in wrong way, because I receive toString() method instead of class binded fields.
That's my resources with defined style:
<UserControl.Resources>
<ItemsPanelTemplate x:Key="VirtualizingStackPanelTemplate">
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
<ListView x:Key="ListBoxTemplate" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ListBoxItem Background="DarkOrchid" Margin="1,1, 5,5" Height="400" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">-->
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Title}"/>
<TextBlock FontSize="20" Text="{Binding Desc}"/>
</StackPanel>
<!--</ListBoxItem>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</UserControl.Resources>
Here is my method in which i add listview programatically:
long rowCount = ContentGridFullView.RowDefinitions.LongCount();
if (rowCount > 8) return;
var c1 = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) };
ContentGridFullView.RowDefinitions.Add(c1);
rowCount = ContentGridFullView.RowDefinitions.LongCount();
TextBlock tb = new TextBlock {Text = "TEXTBLOCK ITEM = " + (rowCount - 1), FontSize = 40};
Viewbox vb = new Viewbox { Child = tb };
if (rowCount > 8) return;
Grid.SetRow(vb, Convert.ToInt32(rowCount-1));
Grid.SetColumn(vb, 1);
ListView lb = new ListView();
lb.Style = Resources["ListBoxTemplate"] as Style;
lb.ItemsPanel = (ItemsPanelTemplate) Resources["VirtualizingStackPanelTemplate"];
var products = new ObservableCollection<Product>() { new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC") };
lb.ItemsSource = products;
ContentGridFullView.Children.Add(lb);
ContentGridFullView.Children.Add(vb);
Grid.SetRow(lb, Convert.ToInt32(rowCount - 1));
Grid.SetColumn(lb, 2);
And my short class that I want to bind:
public class Product
{
public string Title { get; set; }
public string Desc { get; set; }
public Product(string title, string desc)
{
Title = title;
Desc = desc;
}
public override string ToString()
{
return "I see that message instead of Title and Desc";
}
}
Can someone tell me what's wrong with this code? Thank you.
Create your Observable collection as a property (getter/setter):
ObservableCollection<Product> _products;
public ObservableCollection<Product> products
{
get{return _products;}
set
{
_products=value;
PropertyChanged("products");
}
}
The property changed event will be need to indicate that the collection has changed,its needed when your using ObservableCollection. You'll need to read more about it.You can add items to the products collection by using :
products.Add(Product_object)
And your xaml code will have the itemsSource as follows:
<ListView x:Key="ListBoxTemplate" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Visible" ItemsSource="{Binding products}">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ListBoxItem Background="DarkOrchid" Margin="1,1, 5,5" Height="400" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">-->
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Title}"/>
<TextBlock FontSize="20" Text="{Binding Desc}"/>
</StackPanel>
<!--</ListBoxItem>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The following statement is important in your xaml code so that your xaml code will know where to look for the data.
DataContext="{Binding RelativeSource={RelativeSource Self}, Path=x}
First try and create a static list and check if data is getting initialized properly and then you can try creating listviews dynamically. But the code above will be the same thing you will have to do create dynamic listviews.

How to Display Gridview items with variable width in Windows 8?

My GridView items having the size of it's first item size. How do i can change this behaviour ?
How to display GridView items with variable Width as per the content ?
I want to show the first one but i am getting second one. Any suggestion to do that?
Check Windows 8 GridView and Variable-Sized Items and Different Sized Tile Items in WinRT GridView and also check Variable Sized Grid Template Hope this help
You can create such view of GridView by setting ItemsPanel to WrapPanel, you can get WrapPanel on Jerry Nixon's blog. Here's the code.
XAML
<GridView x:Name="gv">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Height="140" Width="{Binding MyWidth}">
<Grid.Background>
<SolidColorBrush Color="{Binding MyColor}" />
</Grid.Background>
<TextBlock FontSize="20" VerticalAlignment="Bottom" Margin="10,0,0,10">
<Run Text="{Binding MyWidth}" />
</TextBlock>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
C#
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var list = new List<ViewModel>()
{
new ViewModel(110, Colors.LawnGreen),
new ViewModel(50, Colors.DarkBlue),
new ViewModel(130, Colors.Firebrick),
new ViewModel(60, Colors.RosyBrown),
new ViewModel(100, Colors.IndianRed),
new ViewModel(210, Colors.BurlyWood),
new ViewModel(150, Colors.Turquoise)
};
gv.ItemsSource = list;
}
public class ViewModel
{
public double MyWidth { get; set; }
public Color MyColor { get; set; }
public ViewModel(double _MyWidth, Color _MyColor)
{
MyWidth = _MyWidth;
MyColor = _MyColor;
}
}
Here is my solution.
//variable sized grid view
public class VariableSizedGridView : GridView
{
protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item)
{
try
{
dynamic gridItem = item;
var typeItem = item as CommonType;
if (typeItem != null)
{
var heightPecentage = (300.0 / typeItem.WbmImage.PixelHeight);
var itemWidth = typeItem.WbmImage.PixelWidth * heightPecentage;
var columnSpan = Convert.ToInt32(itemWidth / 10.0);
if (gridItem != null)
{
element.SetValue(VariableSizedWrapGrid.ItemWidthProperty, itemWidth);
element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, columnSpan);
element.SetValue(VariableSizedWrapGrid.RowSpanProperty, 1);
}
}
}
catch
{
element.SetValue(VariableSizedWrapGrid.ItemWidthProperty, 100);
element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, 1);
element.SetValue(VariableSizedWrapGrid.RowSpanProperty, 1);
}
finally
{
base.PrepareContainerForItemOverride(element, item);
}
}
//Collection View source
<CollectionViewSource x:Name="collectionViewSource"
Source="{Binding ImageList,Mode=TwoWay}"
IsSourceGrouped="False"
ItemsPath="Items" />
//variable sized Grid view xaml
<controls:VariableSizedGridView x:Name="ImageGridView"
AutomationProperties.AutomationId="ImageGridView"
ItemsSource="{Binding Source={StaticResource collectionViewSource}}"
IsItemClickEnabled="True"
TabIndex="1" >
<controls:VariableSizedGridView.ItemTemplate>
<DataTemplate>
<Grid Height="300" >
<Image Stretch="Uniform" Source="{Binding WbmImage}" />
</Grid>
</DataTemplate>
</controls:VariableSizedGridView.ItemTemplate>
<controls:VariableSizedGridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid ItemWidth="10" ItemHeight="300" Orientation="Vertical"/>
</ItemsPanelTemplate>
</controls:VariableSizedGridView.ItemsPanel>
</controls:VariableSizedGridView>

Stackpanel/Itemscontrol Databinding

I have this XAML:
<ItemsControl x:Name="recentSearches"
Margin="0,65,0,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding q}"
TextWrapping="Wrap"
Foreground="AliceBlue"
Padding="2,6,2,2"
Margin="12,-6,12,0"
FontSize="20" />
</DataTemplate>
</ItemsControl.ItemTemplate>
and this code behind:
private void showLatestSearches()
{
if (fmn.checkLatestSearchesExtistence())
{
List<RecentSearchItem> recent = new List<RecentSearchItem>();
List<String> l = fmn.readLatestSearches();
for (int i = 0; i <= l.Count-1; i += 1)
{
RecentSearchItem r = new RecentSearchItem();
r.q = l[i];
r.generalbg = grau;
recent.Add(r);
}
recentSearches.DataContext = recent;
}
}
the object called fmn reads a .txt from the isolated storage.
But why doesn't anything show up with this StackPanel?
ItemsControl.ItemsSource has to be bound to a collection, for notifications the best would be ObservableCollection<T>.
You are setting the DataContext at the last possible minute, a better way would be to set
DataContext to a ViewModel, could be place where you create your View.
public class Form :UserControl
{
DataContext = new YourViewModel() ;
}
In XAML:
ItemsSource="{Binding SearchesCollection}"
SearchesCollection would be a property in YourViewModel of type ObservableCollection<string>. Whenever you add a new item to SearchesCollection the View updates.
This Databinding Tutorial should help.
Thanks to Lews Therin I managed to finally bind my data to the stackpanel:
<ItemsControl x:Name="recentSearches"
ItemsSource="{Binding recent}"
Background="{Binding generalbg}"
Margin="0,65,0,0" Tap="recentSearches_Tap">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding q}"
Foreground="{Binding foreground}"
TextWrapping="Wrap"
Padding="2,6,2,2"
Margin="12,-6,12,0"
FontSize="20" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
and the code behind:
private void showLatestSearches()
{
if (fmn.checkLatestSearchesExtistence())
{
List<RecentSearchItem> recent = new List<RecentSearchItem>();
List<String> l = fmn.readLatestSearches();
for (int i = 0; i <= l.Count-1; i += 1)
{
RecentSearchItem r = new RecentSearchItem();
r.q = l[i];
r.generalbg = grau;
r.foreground = blau;
recent.Add(r);
}
recentSearches.ItemsSource = recent;
}
}
this works, but unfortunately there seems to be no way to determine, which TextBox is tapped, when one is tapped.

Categories