I'm trying to create something looking like this :
It's designed to be an XAML title for VMIX software, video broadcasting purposes.
I'm gonna get a lot of datas from a GSheet, handle in VMIX, and assign those datas to my TextBlocks such as "Candidate", "City" and the Votes %.
From that % I want the bar size to increase/decrease, I managed to do part of that.
But the main issue is to get the % TextBlock margin to fit on the right of the rectangle.
Anyone knows how I could do that ?
I have never been coding in C#, I have a background in C, C++ and JS, so I've spent my day looking for that purpose and couldn't make it right.
I saw some binding methods that could fit, but I'm unable to use them.
Moreover I'm working on Blend for Visual Studio 2017, and I don't get why I can't run some simple code on it when pressing F5... It's another problem thought.
Thanks a lot for your help.
EDIT :
I've reached something new so far, really DIY solution but it's my lsat solution if I can't find better :
I'll have 2 TextBlock for 1 ProgressBar (Thanks to Chris)
<Grid Margin="0,0,-8,0">
<TextBlock x:Name="Votes1" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="{Binding Text, ElementName=MarginVotes1}" FontSize="72" Width="853" Height="188"><Run Text="6"/><Run Text="00"/></TextBlock>
<ProgressBar HorizontalAlignment="Left" Height="79" Margin="171,503,0,0" VerticalAlignment="Top" Width="{Binding Path=Text, ElementName=Votes1}" Background="#FFEA4545"/>
<TextBlock x:Name="MarginVotes1" HorizontalAlignment="Left" Margin="171,587,0,0" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="72" Height="98" Width="550"><Run Text="8"/><Run Text="0"/><Run Text="0"/><Run Text=","/><Run Text="4"/><Run Text="9"/><Run Text="0"/><Run Text=",0,0"/>
</TextBlock>
So this works fine, but I have to prepare before what my "MarginVotes1" value is (in GoogleSheet).
The best would be directly in code behind to do something like this :
CONVERT Votes1.Text to Int STORE in val
SET x to val + DefaultMargin
CONVERT x to String STORE in MarginX
CREATE String MarginVoteStr as MarginX + ",500, 0, 0"
SET Votes1.Margin as MarginVoteStr
Welcome to WPF. Here's some code I put together that you should be pretty close to what you need.
XAML:
<ItemsControl Grid.IsSharedSizeScope="True" ItemsSource="{Binding Candidates}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Candidate" Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}"/>
<Rectangle Grid.Column="1" Height="10" Margin="5, 0" Width="{Binding BarWidth}" Fill="{Binding BarColor}"/>
<TextBlock Grid.Column="2" Text="{Binding Percentage, StringFormat=P}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
C#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Candidates = new List<Candidate> { new Candidate { Name = "Joe", Percentage = .50, BarColor = Brushes.Green},
new Candidate { Name = "Bob", Percentage = .30, BarColor = Brushes.Yellow},
new Candidate { Name = "Sarah", Percentage = .20, BarColor = Brushes.Gray}};
}
public List<Candidate> Candidates
{
get { return (List<Candidate>)GetValue(CandidatesProperty); }
set { SetValue(CandidatesProperty, value); }
}
public static readonly DependencyProperty CandidatesProperty =
DependencyProperty.Register("Candidates", typeof(List<Candidate>), typeof(MainWindow));
}
public class Candidate
{
public string Name { get; set; }
public double Percentage { get; set; }
public Brush BarColor { get; set; }
//This is just shorter syntax for a readonly property.
//The multiplier (200) should be whatever length you want a full bar to be
public double BarWidth => Percentage * 200;
}
There are a number of points you should note:
ItemsControl and DataTemplate
Whenever you need to display multiple data items in WPF, especially if the number of items is variable, you should be using some type of ItemsControl.
An ItemsControl takes a collection of some kind and displays each item using a DataTemplate. An ItemsControl creates a new instance of its ItemTemplate for every item in its source collection. The link between the data and the visuals is established through data bindings.
Layout
Everything between the <DataTemplate> tags is the visual layout of a single item.
Notice that I am not using Margin to create the desired layout. Instead of using Margin in that way, I'm using one of WPFs many Panel controls: Grid. With Grid you can define rows and columns like a table.
Each item in my example is a Grid with 1 row and 3 columns. The elements that make up the item are placed in that grid using the Grid.Column property. Each column has Width="Auto", which means it will grow to accommodate the width of what's inside. IsSharedSizeScope and SharedSizeGroup make it so that the Grids of each individual item all have the same width for the first column.
Candidate class
This is the class that will be used to store and represent the data being displayed. Note that the property names match the {Binding ______} values from the DataTemplate.
My example main window has a collection of Candidate objects stored in a dependency property. This property is bound to the ItemsSource of the ItemsControl.
Overall
The idea is to populate your collection with whatever data items you need and let the ItemsControl take care of the rest, thus keeping the data and visuals of the project relatively independent. Even small visual aspects like formatting the percentage value correctly for display can be done using the DataTemplate instead of writing the code in C#, as shown using StringFormat=P.
Related
I have a ListView that is intended to show every product within a database, and it works for the most part, but when I scroll down by dragging the scroll bar, the bottom items end up being incorrect.
XAML Definition:
<ListView x:Name="lst_Products" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="16,124,16,16" Width="300" ContainerContentChanging="lst_Products_ContainerContentChanging" Loaded="lst_Products_Loaded" BorderBrush="Black" BorderThickness="2" CornerRadius="16">
<ListView.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Value}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The data template is present so I can easily grab a product ID number with SelectedValue. According to some trusted community member (or whatever they call the prominent posters) on the MSDN forums said that's the only way to properly show a ListView when the ItemsSource is an ObservableCollection<KeyValuePair<int,RelativePanel>> while having a selectable value member.
The relevant C# code:
private async void lst_Products_Loaded(object sender, RoutedEventArgs e)
{
var products = await ProductManager.GetProducts();
ObservableCollection<KeyValuePair<int, RelativePanel>> productList = new(products);
lst_Products.ItemsSource = productList;
lst_Products.SelectedValuePath = "Key";
}
private void lst_Products_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (args.ItemIndex % 2 == 1)
{
args.ItemContainer.Background = new SolidColorBrush(Color.FromArgb(128, 128, 128, 128));
}
else
{
args.ItemContainer.Background = UIManager.GetDefaultBackground();
}
}
public static async Task<List<KeyValuePair<int, RelativePanel>>> GetProducts()
{
var productPanels = new List<KeyValuePair<int, RelativePanel>>();
var productIDs = await SqlHandler.ReturnListQuery<int>($"SELECT id FROM {productTable}");
var productNames = await SqlHandler.ReturnListQuery<string>($"SELECT name FROM {productTable}");
var panels = new List<RelativePanel>();
foreach(var name in productNames)
{
RelativePanel panel = new();
TextBlock productName = new()
{
Text = name
};
panel.Children.Add(productName);
panels.Add(panel);
}
for(int i = 0; i < productIDs.Count; i++)
{
productPanels.Add(new KeyValuePair<int, string>(productIDs[i], panels[i]));
}
return productPanels;
}
The call to SQL Handler just runs an SQL query and returns a list of the results. I can post the code if you need, but I can assure you there's no sorting going on.
A screenshot of what the list looks like. The bottom item should be "Coffee" - Button Test Product 2 is the second item in the list.
A screenshot of the SQL datatable with the "Coffee" product at the bottom where it should be.
In this case it's just the bottom item that's incorrect, however other times it has jumbled 5 or 6 entries near the bottom. This only seems to occur with the DataTemplate/ContentPresenter, but without that, the RelativePanel does not display correctly in the list. Eventually the list will show more information about the product and as far as I can tell, there's no good way to do that without converting the SQL data into a RelativePanel on the c# side.
I'm open to suggestions on solving either the jumbling problem with the template, or adjusting the xaml so that I don't need the template to display bulk sql data without needing the template but I'm at a loss.
c# - UWP ListView displays incorrect items upon rapid scrolling when it has a DataTemplate
The problem should be caused by listview virtualization, There are two ways to sloved this prolbem, one is disalbe listview virtualization by setting ItemsPanel as StackPanel like the following
<ListView>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
And the other way is implement INotifyCollectionChanged interface for your model class. for more please refer to Data binding in depth
It's not good practice that useRelativePanel collection as datasoure, the better way is make RelativePanel in your DataTemplate and bind with mode class property.
For example
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Index}" />
<TextBlock Text="{Binding IsItem}" />
<Image Source="{Binding ImageSource}" Visibility="Collapsed" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
I am working on Windows 8 application in C#/XAML.
I have a list of steps to show and the list can have one to many steps.
I have tried the GridView and ListView controls, but with those, it is not possible to have each element have its own height (because one step might have only one line of text, and the next one 3 lines, for example). The VariableSizedGridview does not help either.
What I am trying to achieve is something like the way cooking steps are shown in the Microsoft Bing Food & Drink app. So, steps are shown in rows in the first column, and when the end of the page is reached, it creates a second column, and so on. Like so :
Could anyone please help me find a way to achieve this?
What control to use and how?
It looks very simple, but I was not able to find any solution while searching online.
Thank you
Here is what I have done with the Gridview control (the Listview was quite similar) :
<Grid Name="gridSteps" Grid.Column="3" Margin="25,69,25,69">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="ÉTAPES" FontSize="22" FontWeight="Bold"></TextBlock>
<GridView Grid.Row="1" Name="gvGroupSteps" SelectionMode="None" IsHitTestVisible="False" VerticalAlignment="Top">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Width="400">
<TextBlock Text="{Binding Order}" Margin="0,15,0,0" FontSize="20" Foreground="Bisque"></TextBlock>
<TextBlock Text="{Binding Description}" Margin="0,5,0,0" FontSize="18" TextWrapping="Wrap"></TextBlock>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Background="#FFC9C9C9">
<TextBlock Text="{Binding GroupName}" FontSize="20" FontWeight="SemiBold"></TextBlock>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</Grid>
You may want to post the XAML that you have tried. It sounds like to me that you need to nest your view items. Consider this very simple example:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ListView>
<ListViewItem>Step 1</ListViewItem>
<ListViewItem>
<ListView>
<ListViewItem>Step 1a</ListViewItem>
<ListViewItem>Step 1b</ListViewItem>
<ListViewItem>Step 1c</ListViewItem>
</ListView>
</ListViewItem>
<ListViewItem>Step 2</ListViewItem>
</ListView>
</Grid>
I have tried the GridView and ListView controls, but with those, it is not possible to have each element have its own height
My recollection is that you can in fact have elements with different heights using those controls. These are both types of ItemsControl, which supports data templating, which in turn allows you to customize the appearance of each item, including its height.
That said, you may find that the simpler ListBox suits your needs in this case. It's hard to say without a code example or other details.
You should read MSDN's Data Templating Overview, which has a thorough discussion of the whole process, along with some good examples of what you can do. Pay particular attention to the section named "Choosing a DataTemplate Based on Properties of the Data Object". While a single template could still have variable height, clearly by using a different template according to your specific needs you can customize each item's style to your heart's content.
If this does not address your question, please provide a more detailed question. You should include a good, minimal, complete code example that shows clearly what you've tried, explaining precisely what that code does and how that's different from what you want it to do.
I have been looking all over the internet for a solution, but could not manage to find anything.
So i decided to do everything myself in C# code.
In short, in have a StackPanel with Orientation set to Horizontal, and I add a Grid to it and add rows to that Grid for every item i have. When the maximum height is reached (based on the screen Height), I add a new Grid to the StackPanel, and so on.
Here is my code if anyone needs it :
// Nombre de lignes maximal (16 lignes à 1080p)
int maxCharCount = (int)Window.Current.Bounds.Height * 16 / 1080;
spIngredients.Children.Clear();
foreach (var groupIngredient in db.Table<GroupIngredient>().Where(x => x.RecipeId == _currentRecipe.Id))
{
int linesCount = 0;
int row = 0;
var gGroup = new Grid();
spIngredients.Children.Add(gGroup);
gGroup.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var groupName = new TextBlock() { Text = groupIngredient.Name, FontSize = 20, FontWeight = FontWeights.SemiBold, Margin = new Thickness(10) };
gGroup.Children.Add(groupName);
Grid.SetRow(groupName, row);
foreach (var ingredient in db.Table<Ingredient>().Where(x => x.GroupIngredientId == groupIngredient.Id))
{
// Nombre de lignes, split à 45 char
linesCount += 1 + ingredient.IngredientFull.Length / 45;
if (linesCount >= maxCharCount)
{
var gCol = new Grid();
spIngredients.Children.Add(gCol);
gCol.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var col = new TextBlock() { Text = "", FontSize = 20, FontWeight = FontWeights.SemiBold, Margin = new Thickness(10) };
gCol.Children.Add(col);
gGroup = gCol;
row = 0;
linesCount = 0;
Grid.SetRow(col, row);
}
row++;
ingredient.Quantity = ingredient.Quantity * multiplier;
gGroup.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var ingredientName = new TextBlock() { Text = ingredient.IngredientFull, Margin = new Thickness(10), FontSize = 18, TextWrapping = TextWrapping.Wrap, MaxWidth = 300 };
gGroup.Children.Add(ingredientName);
Grid.SetRow(ingredientName, row);
}
}
I want to layout my items in a Windows Phone 8.1 app, not silverlight, in the following order:
I did some research and tried different panels, but I can't find the right ones :[
I could use a grid and achive that design, BUT I want to add items over a binding and then I would have to change the grid somehow :/
xaml Layout
<Page.DataContext>
<uc:Test/>
</Page.DataContext>
<ScrollViewer>
<ItemsControl ItemsSource="{Binding t}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Aqua"
BorderThickness="3"
Width="100" Height="100">
<TextBlock Text="{Binding}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
test.cs
public class Test
{
public ObservableCollection<string> t { get; set; }
public Test()
{
t = new ObservableCollection<string>();
t.Add("a");
t.Add("b");
t.Add("c");
t.Add("d");
t.Add("e");
}
}
Edit:
ALSO, I did write a wrong information in the comment below, sorry.
Every Item has the same width, so count and width, will/would give me the position in column and row.
Implementation of PrepareContainerForItemOverride so far:
public class ExtendedItemsControl : ItemsControl
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var grid = element as ContentPresenter;
var count = 0; // <- Count of Items in the Grid
var width = 0; // <- width of the current Element
//if (count * width / grid.ActualWidth > 1)
// grid.RowDefinitions.Add(new RowDefinition());
Grid.SetRow(grid, 0);
}
}
You can use a Grid along with an ItemsControl to achieve the ItemsSource binding:
First, set the Grid as the ItemsControl's ItemsPanel
Second, subclass the ItemsControl to set the appropriate Grid.Row and Grid.Column properties on its children
For the first part (it looks from the picture like you have 4 columns and 3 rows):
<local:ExtendedItemsControl ItemsSource="{Binding MyItems}">
<local:ExtendedItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</local:ExtendedItemsControl.ItemsPanel>
</local:ExtendedItemsControl>
For the second part, I suggest overriding OnItemsChanged, and setting the Grid attached properties on each item container as needed. You could do this by using the implicit sequence of the items:
public class ExtendedItemsControl : ItemsControl
{
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
var item2 = this.ItemContainerGenerator.ContainerFromItem(e.NewItems[1]);
Grid.SetColumn(item2, 1);
var item3 = this.ItemContainerGenerator.ContainerFromItem(e.NewItems[2]);
Grid.SetColumn(item3, 2);
Grid.SetColumnSpan(item3, 2);
var item4 = this.ItemContainerGenerator.ContainerFromItem(e.NewItems[3]);
Grid.SetRow(item4, 1);
// etc ...
}
}
The above assumes that your source collection doesn't not change once bound -- if it does change, you might consider overriding PrepareContainerForItemOverride instead, and setting its Grid Row/Column properties with reference to a property on the item model ("ItemIndex" or whatever):
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var contentPresenter = (ContentPresenter)element;
var itemModel = (MyItemModel)item;
switch (itemModel.ItemIndex)
{
case 1:
Grid.SetColumn(contentPresenter, 1);
break;
case 2:
Grid.SetColumn(contentPresenter, 2);
Grid.SetColumnSpan(contentPresenter, 2);
break;
// etc
}
}
There isn't a standard control that will give you the layout you want for arbitrary numbers of different sized items without some custom placement code, but you can customize controls depending on what exactly you need.
Mark Rideout created a customized GridView sample for Windows Store 8.0 at How To: Create a Variable Sized Grouped GridView (like the store) and the techniques you'll use for a Windows Phone Runtime app will be essentially the same. In his control he overrode the PrepareContainerForItemOverride function to look at the individual data items to see if they should be small, medium, or large sized, and then set their columns and spans appropriately in a VariableSizedWrapGrid.
If you want the exact positioning you show (rather than lining things up) and want to limit to 7 then you could set the ItemsPanel to a Grid instead of the VariableSizedWrapGrid and set the items into specific rows and columns in the same way.
Since my issue is rather uncommon and I have not a single clue what could be causing it, I will try to include every code that might have anything to do with it, stripped down to the very essentials to avoid unnecessary clutter.
Basically, I have a TabControl that includes TabItems whoes Contents are custom UserControls.
Those controls are of the following form:
<UserControl>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinition>
<ScrollViewer Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="scrollViewer11" VerticalAlignment="Stretch" Width="Auto" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"></ScrollViewer>
<ScrollViewer Grid.Column="1" Height="Auto" Name="scrollViewer12" Width="Auto" Margin="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"></ScrollViewer>
<ScrollViewer Grid.Row="1" Height="Auto" Name="scrollViewer21" Width="Auto" Margin="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"></ScrollViewer>
<ScrollViewer Grid.Row="1" Grid.Column="1" Height="Auto" Name="scrollViewer22" Width="Auto" Margin="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"></ScrollViewer>
</Grid>
</UserControl>
The amount of rows and columns depends on the control used and ranges from a single cell in a 1x1 grid to 6 cells in a 3x2 grid (each contraining the ScrollViewer).
Now to my actual C# code. To each cell the user may add a WriteableBitmap where the code is organized as such:
public partial class MainWindow : Window
{
List<WorkSpace> WorkSpaceList = new List<WorkSpace>();
private WorkSpace currentSpace = null;
//one of the methods that adds to the TabControl, here a 2x2 grid:
private void NewWorkspaceFour(WorkSpace ws)
{
WorkSpaceFour workSpaceFour = new WorkSpaceFour();
for (int i = 0; i < 4; i++)
{
WorkPlace wp = new WorkPlace();
ws.workPlaceList.Add(wp);
switch (i)
{
case 0:
workSpaceFour.scrollViewer11.Content = wp.grid;
break;
case 1:
workSpaceFour.scrollViewer12.Content = wp.grid;
break;
case 2:
workSpaceFour.scrollViewer21.Content = wp.grid;
break;
case 3:
workSpaceFour.scrollViewer22.Content = wp.grid;
break;
}
}
ws.tabItem.Content = workSpace;
tabControlImages.Items.Add(ws.tabItem);
}
//triggered in UI e.g. by moving a Slider
private void NewSettings(object sender, RoutedPropertyChangedEventArgs<double> e)
{
currentSpace.NewSettings((float)(e.NewValue));
}
}
internal class WorkSpace
{
internal delegate void NewSettingHandler(float e);
internal List<WorkPlace> workPlaceList = new List<WorkPlace>();
internal TabItem tabItem = new TabItem();
internal WorkPlace currentPlace = null;
internal NewSettingsHandler NewSettings;
internal WorkSpace()
{
NewSettings += ChangeSettings;
}
internal void ChangeSettings(float newValue)
{
//do something small with newValue
currentPlace.RecalculateImage();
}
//...more methods that would use "newValue" in a different way, thus the delegate
}
internal class WorkPlace
{
internal WriteableBitmap bitmap;
internal Image image = new Image {//settings};
internal Grid grid = new Grid {//settings};
internal Grid gridImage = new Grid {//settings};
internal WorkPlace()
{
grid.Children.Add(gridImage);
gridImage.Children.Add(image);
}
internal void RecalculateImage()
{
//some rather long calculations...
bitmap.WritePixels(...,...,...,...);
image.Source = bitmap;
}
}
Through the program the user can change the tabs to change currentSpace and click on the cells to change the respective currentPlace both simply by change the reference i.e. currentSpace = space, where space refers to the WorkSpace that contains the new selected TabItem.
Now the issue is as follows. When a tab contains a simple 1x1 grid with an image in it and I move the slider, it runs very smoothly. When a tab contains a 3x2 grid and only a single cell of this grid contains a WorkPlace with a bitmap that is not null it works the same. However, when the 3x2 grid is completely filled with "painted" bitmaps and the slider is moved a noticable lag appears, even though only a single of the 6 images is recalculated redrawn. I don't see why this should be the case. It might have something to do with rendering or the object references but I don't know C# well enough to see and issues here.
Hopefully, the code is not too long (I have stripped it down as much as I could) and clear enough. If anything is not, please say so and I will update/add it. In a previous version of this program the UI was basically the same but the recalculation of the images was fairly different but I could never observe this problem.
I am working on windows phone 8 app.
I have List box with over 200 items to display.
<DataTemplate x:Key="DataTemplate1">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="White" Height="400" Width="400" CornerRadius="30,30,30,30">
</Border>
<Grid Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Top">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="5,20,5,5"
Foreground="#000000"
Text="{Binding Title}"/>
</Grid>
</Grid>
</DataTemplate>
But it crashes, i have debugged it till 100 items it works but after that it crashes.
In the PhoneApplicationPage_Loaded method i have
private void PhoneApplicationPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
myList.Add(new MyObject("A","A value"));
myList.Add(new MyObject("B", "B value"));
myList.Add(new MyObject("C", "C value"));
and so on... 200 items
ListBoxItems.ItemsSource = myList;
}
how can i fix this ?
Update :
<ItemsPanelTemplate x:Key="ItemsPanelTemplate">
<local:CollectionFlowPanel ItemHeight="400"
ItemWidth="400"
FocusedItemOffset="120"
UnfocusedItemOffset="20"
ItemVisibility="5">
<VirtualizingStackPanel />
</local:CollectionFlowPanel>
</ItemsPanelTemplate>
</phone:PhoneApplicationPage.Resources>
<Grid x:Name="LayoutRoot" Background="#000000">
<local:CollectionFlow x:Name="ListBoxItems"
ItemTemplate="{StaticResource DataTemplate}"
ItemsPanel="{StaticResource ItemsPanelTemplate}"/>
</Grid>
Ensure you have VirtualizingStackPanel inside the ItemsPanelTemplate of your list box, see this answer for more info.
Here's the XAML you likely need for your ListBox:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
You need to read following blog from msdn on visualization of the data in list and grid.
Using virtualization with a list or grid
Without seeing your whole xaml code I cannot suggest the exact answer but my guess is that you in xaml ListBox is placed inside a canvas/StackPanel or scrollviewer control.
When the size of the ItemsControl's viewport isn't restricted, the control doesn't perform virtualization. Instead, it creates an item container for each item in its collection. Some common containers that don't restrict the viewport size are Canvas, StackPanel, and ScrollViewer. You can enable virtualization in this situation by setting the size of ItemsControl directly, instead of letting it be sized by its parent container.
Here, we set the Height and Width on the GridView. This restricts the size of the viewport, and items outside of the viewport are virtualized.
Below are 2 scenarios one will throw out of memory exception and other will work fine(use your same code behind and test)
1. ListBox in Canvas
<Canvas .....
<ListBox Name="ListBoxItems".....
</ListBox>
</Canvas>
Above code will throw out of memory exception as items control's viewport is not defined (if you still want to use Canvas than define width/height if ListBox in that case the port of Items control is defined and virtulazation will apply)
2. ListBox in Grid
<Grid .....
<ListBox Name="ListBoxItems".....
</ListBox>
</Grid>
The above code will not throw out of memory exception as virtuallization is applied on the listbox.
Hope this will help
How big is your object ? If your object is too big you might not be able to load them all at once.
Did you try using the for loop?
public List<Fellow> fellowList { get; set; }
private void PhoneApplicationPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
fellowList = new List<Fellow>();
for (int i = 0; i < 2; i++)
{
Fellow fellow = new Fellow();
fellow.x = "B" + i;
fellow.value = "B Value" + i;
fellowList.Add(fellow);
}
this.DataContext = this;
ListBoxItems.ItemsSource = fellowList;
}
public class Fellow
{
public string x { get; set; }
public string value { get; set; }
}
Hope it helps..change the view model according to your wish