Treeview with multi colour node text - c#

I have a project that requires the use of a treeview control. The control must have the ability for the text on each node to be formatted so the text can be multi coloured. This is best shown by the treeview used in outlook - see pic )
I historically have a windows forms control that I created to do this, my question is how easy is this to do in WPF without having to use 3rd party controls?

I historically have a windows forms control that I created to do this
Forget winforms, it's a dinosaur technology that has not been improved since 2007, it is not intended to create Rich UIs (only poor ones), and that does not support anything and forces you to write too much code and achieve less. It does not support any kind of customization and is slow as hell.
All the horrible hacks required in winforms to do anything (such as "owner draw" and "P/Invoke", whatever that means) are completely irrelevant and unneeded in WPF.
I dont really want to invest a lot of time moving of winforms to wpf if what I want to do is either not possible or too difficult
People are doing things like this in WPF, which are completely impossible in winforms, so what you're talking about here is really a "piece of cake" for WPF.
First of all, if you're getting into WPF, you must forget the traditional too-much-code-for-anything winforms approach and understand and embrace The WPF Mentality.
Here is how you implement that in WPF:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<TreeView ItemsSource="{Binding}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<DockPanel>
<!-- this Image Control will display the "icon" for each Tree item -->
<Image Width="18" Height="16" Source="{Binding ImageSource}"
DockPanel.Dock="Left" Margin="2"/>
<!-- this TextBlock will show the main "Caption" for each Tree item -->
<TextBlock Text="{Binding DisplayName}" FontWeight="Bold"
VerticalAlignment="Center"
x:Name="DisplayName" Margin="2"/>
<!-- this TextBlock will show the Item count -->
<TextBlock Text="{Binding ItemCount, StringFormat='({0})'}"
VerticalAlignment="Center" Margin="2" x:Name="ItemCount">
<TextBlock.Foreground>
<SolidColorBrush Color="{Binding ItemCountColor}"/>
</TextBlock.Foreground>
</TextBlock>
</DockPanel>
<HierarchicalDataTemplate.Triggers>
<!-- This DataTrigger will hide the ItemCount text
and remove the Bold font weight from the DisplayName text
when ItemCount is zero -->
<DataTrigger Binding="{Binding ItemCount}" Value="0">
<Setter TargetName="ItemCount" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="DisplayName" Property="FontWeight" Value="Normal"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Window>
Code Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = DataSource.GetFolders();
}
}
Data Item:
public class Folder
{
public Folder(string displayName)
{
ImageSource = DataSource.Folder1;
Children = new List<Folder>();
ItemCountColor = "Blue";
DisplayName = displayName;
}
public Folder(string displayName, int itemCount): this(displayName)
{
ItemCount = itemCount;
}
public string DisplayName { get; set; }
public int ItemCount { get; set; }
public List<Folder> Children { get; set; }
public string ItemCountColor { get; set; }
public string ImageSource { get; set; }
}
DataSource class (A lot of boilerplate code that generates the tree entries and is not really part of the WPF side of things):
public static class DataSource
{
public const string Folder1 = "/folder1.png";
public const string Folder2 = "/folder2.png";
public const string Folder3 = "/folder3.png";
public const string Folder4 = "/folder4.png";
public static List<Folder> GetFolders()
{
return new List<Folder>
{
new Folder("Conversation History"),
new Folder("Deleted Items",102)
{
ImageSource = Folder2,
Children =
{
new Folder("Deleted Items #1"),
}
},
new Folder("Drafts",7)
{
ImageSource = Folder3,
ItemCountColor = "Green",
},
new Folder("Inbox",7)
{
ImageSource = Folder4,
Children =
{
new Folder("_file")
{
Children =
{
new Folder("__plans"),
new Folder("_CEN&ISO", 5),
new Folder("_DDMS", 1)
{
Children =
{
new Folder("Care Data Dictionary"),
new Folder("HPEN"),
new Folder("PR: Data Architecture"),
new Folder("PR: Hospital DS", 2),
new Folder("RDF"),
new Folder("Schemas"),
new Folder("Subsets"),
}
},
new Folder("_Interop")
{
Children =
{
new Folder("CDSA", 1),
new Folder("CPIS", 2),
new Folder("DMIC"),
new Folder("EOL"),
new Folder("... And so on..."),
}
}
}
}
}
}
};
}
}
Result:
As you can see, this full working sample consists of 30 lines of XAML, 1 line of C# code behind, and a simple POCO class that represents the folder structure, which consists of string, bool, int and List<T> properties and does not have any dependencies on the UI framework at all, plus the DataSource boilerplate, that does not have anything to do with WPF anyways.
Notice how my C# code is clean and simple and beautiful and does not have any horrible "owner draw" stuff or anything like that.
Also notice how the Data/Logic are completely decoupled from the UI, which gives you a HUGE amount of flexibility, scalability and maintainability. You could completely rewrite the UI into a totally different thing without changing a single line of C# code.
There is 1 line of Code behind, which sets the DataContext to a List<Folder>, the rest is achieved via DataBinding into the HierarchicalDataTemplate that defines the Visual structure of the Tree items.
This is the WPF way, to use DataBinding to simplify your life instead of a bunch of useless boilerplate piping to pass data between the UI and the Data Model.
Keep in mind that you can put literally anything inside the DataTemplate, not just text, not just read-only content. You can even put editable controls or even Video inside each tree item. the WPF Content Model does not suffer from the huge limitations imposed by other technologies.
WPF Rocks - just copy and paste my code in a File -> New Project -> WPF Application and see the results for yourself, you will need to add the png files and set their Build Action to Resource in your project:
Once you know WPF, XAML and MVVM, you will NEVER want to go back to winforms again, and you'll realize how much valuable time you've lost all these years using dead technology.

Related

WPF and array of datagrids

I'm trying to develop something that - with WinForms - would be a proverbial "piece of cake". A dynamic set of data-bound datagrids. That initializes on application start. Sometimes there is a need for one, sometimes for five. At first it looked like too much for XAML. So I'm struggling with it with regular C#. which - with WPF - is insanely unfriendly and I'm hitting the wall again and again.
Or am I doing it all wrong? Is there any correct way to... "duplicate" / "clone" one datagrid designed and closed with XAML and reuse those clones as a dynamic array? Whenever I'm looking for a solution to more and more WPF obstacles (i.e. something as simple (with WinForms) as dynamic row coloring), I find sometimes XAML solutions. plain code solutions are extremely rare. even if try to "translate" XAML to regular code, I miss a lot of properties / methods (or maybe they are named differently). anyway - it's like people these days turn to XAML completely. are arrays of more complex controls that uncommon? I found some examples of button array bound to some table. and that's pretty much it. plus it never worked for an array of datagrids...
This is just a prototype of how binding can yield fast results with minimal code written.
<Window x:Class="testtestz.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ItemsControl ItemsSource="{Binding GridViews}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding Data}" BorderBrush="Gray" BorderThickness="1" Margin="5">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Id}" Header="Id"/>
<GridViewColumn DisplayMemberBinding="{Binding Name}" Header="Name"/>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
This is the code behind.
using System.Collections.Generic;
using System.Windows;
namespace testtestz
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<object> myData = new List<object>()
{
new { Id = 1, Name = "John" },
new { Id = 2, Name = "Mary" },
new { Id = 3, Name = "Anna" },
};
GridViews.Add(new MyGrid { Data = myData});
GridViews.Add(new MyGrid { Data = myData });
GridViews.Add(new MyGrid { Data = myData });
DataContext = this;
}
public List<MyGrid> GridViews { get; } = new List<MyGrid>();
}
public class MyGrid
{
public IEnumerable<object> Data { get; set; }
}
}
Keep in mind you can bind almost anything you like so MyGrid class could very well have all the properties needed to create these grids. So for instance, you can have column definitions such as Header texts, column widths and such...

In C# XAML for Windows 8.1 how do I bind styles to a variable?

I've been banging my head against this one for quite some time now, so I figured I'd ask here and see if someone can give me a hand. First off, I'm new to C#, XAML, and Windows 8 programming.
The basic thing I want to do is this: based on a change to the data model (which I'm doing in my little testbed project inside a Button_Click handler), I'd like to change the Foreground value in a <Style>. I have had success in changing the Foreground value in a <TextBlock>, but not on a <Style> that operates on another <TextBlock>.
Here's what I've done (pardon the verbosity, hopefully it makes sense):
I've got a class called MyColorDataSource that I'm using as a binding target in my MyPage.xaml page. Here's the relevant code from that class:
public class MyColorDataSource
{
private MyColors _brush1;
public MyColors Brush1
{
get { return _brush1; }
set { _brush1 = value; }
}
private MyColors _brush2;
public MyColors Brush2
{
get { return _brush2; }
set { _brush2 = value; }
}
public MyColorDataSource()
{
_brush1 = new MyColors();
_brush2 = new MyColors();
_brush1.BrushColor= new SolidColorBrush(Colors.DarkRed);
_brush2.BrushColor = new SolidColorBrush(Colors.Pink);
}
}
You'll notice that the variables in MyColorDataSource are of type MyColors. Here's the definition of that class:
public class MyColors : INotifyPropertyChanged
{
private SolidColorBrush _brushColor;
public SolidColorBrush BrushColor
{
get { return _brushColor; }
set {
if (value != _brushColor)
{
_brushColor = value;
NotifyPropertyChanged("BrushColor");
}
}
}
#region INotifyPropertyChanged Members
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
Debug.WriteLine("in NotifyPropertyChanged for " + propertyName);
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
Here's the XAML I've written, with two <TextBlock> elements, one of which has its Foreground property bound directly to the datasource, and one of which uses a <Style> which I'm trying to bind to the datasource. In MyPage.xaml:
<Page.Resources>
<Style TargetType="TextBlock" x:Key="BoundColor">
<Setter Property="Foreground" Value="{Binding Brush2.BrushColor}" />
</Style>
</Page.Resources>
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock x:Name="TextBlockToFormatWithBinding" Text="Direct Binding" Foreground="{Binding BrushColor}" />
<TextBlock x:Name="TextBlockToFormatWithStyleBinding" Text="Binding through style" Style="{StaticResource BoundColor}"/>
</StackPanel>
I've set up my DataSource variable in App.xaml.cs:
public sealed partial class App : Application
{
public static MyColorDataSource ColorDataSource;
public App()
{
this.InitializeComponent();
this.Suspending += this.OnSuspending;
ColorDataSource = new MyColorDataSource();
}
}
And I access the datasource in MyPage.xaml.cs:
public MyPage()
{
this.InitializeComponent();
App.ColorDataSource.Brush1.BrushColor = new SolidColorBrush(Colors.DarkOliveGreen);
App.ColorDataSource.Brush2.BrushColor = new SolidColorBrush(Colors.DarkKhaki);
this.DataContext = App.ColorDataSource;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
TextBlockToFormatWithBinding.DataContext = App.ColorDataSource.Brush1;
// TextBlockToFormatWithStyleBinding.DataContext = App.ColorDataSource.Brush2; // tried this, it did nothing
}
If you're still with me, thank you! What's happening is that the first <TextBlock> shows up as expected, in a DarkOliveGreen color. The second <TextBlock> does not show up at all, and I'm assuming that its Foreground is defaulting to Black (the page background is also Black, so I can't see it). When I change the Foreground value in the <Style> to something like "DarkRed", voila, it shows up as expected. So the <TextBlock> is definitely there, but it's not getting its Foreground value from the DataModel as I want it to.
Has anyone out there run into this before, and if so, how did you resolve it? I really don't want to have to change each <TextBlock> individually, as I intend to try to style items in a <ListView>, and I really don't want to iterate over all of the <Item>s and change their styling one by one. Having done a lot of HTML/CSS/jQuery, I'm used to being able to style things by class instead of iteratively, one at a time.
Thanks in advance for any help or advice you can offer.
Edit:
I did manage to run across a technique that gets me pretty close to what I'm trying to do here, partially with the help of the answer below (thanks again for that!). Hopefully if someone else comes along with a similar question, this will help out.
<SolidColorBrush x:Key="myBrush" Color="#330000FF" />
<Style TargetType="TextBlock" x:Key="BoundColor">
<Setter Property="Foreground" Value="{StaticResource myBrush}" />
</Style>
Then in my code-behind, I can do something like this:
((SolidColorBrush)Resources["myBrush"]).Color = Color.FromArgb(64, 255, 0, 0);
This doesn't put the color of the element in the data model, per se, but honestly does the color of an element really belong in the data model? I would generally say that it does not.
Note that I didn't have any luck making this technique work on the 'Visibility' <Setter> I tried to put on it (I wanted the TextBlock to be hidden sometimes and visible sometimes), but for colors and other object-based <Setter>s it worked just fine. My supposition based upon the little that I know is that this is true because Visibility is an enum, not class. So while I can put this in my <Page.Resources>:
<Visibility x:Key="TextBlockVisibility">0</Visibility>
and this in the <Style>:
<Setter Property="Visibility" Value="{StaticResource TextBlockVisibility}" />
I don't seem to be able to alter the value of the TextBlockVisibility in such a way that the <Style> will notice or be affected by the change in value.
Sorry, but you can't. Like a number of very useful WPF features (your code works just fine in a WPF program), this is AFAIK not supported on Windows Phone.
That said, you can work around the problem. The most obvious solution is to not use a style in the first place. Another solution is to use a "helper" object as the actual setter value in your style, which itself manages the binding via an attached property being set by the style's setter.
An example of this technique can be found at David Anson's web site, here:
The taming of the phone [New SetterValueBindingHelper sample demonstrates its usefulness on Windows Phone 7 (and Silverlight 4)]
Using that example, your style setter might look something like this:
<Setter Property="delay:SetterValueBindingHelper.PropertyBinding">
<Setter.Value>
<delay:SetterValueBindingHelper
Property="Foreground"
Binding="{Binding Brush2.BrushColor}"/>
</Setter.Value>
</Setter>
(Note: I didn't actually test a working example for your code; you might have to fiddle a bit with the binding itself to get the data context right, as I'm not sure it will correctly inherit the context from the page with the extra indirection.)

Can I access XAML elements in an array in the codebehind?

I've been looking around but I haven't been able to find anything on this. I am trying to get started making Windows 8.1 apps in C# with Visual Studio 2013 Pro. I want to be able to access multiple elements (particularly buttons or text blocks) in an array because this is more convenient for developing things like board games. For instance, if I were developing tic-tac-toe, I might use a series of buttons like this:
<Grid>
<Button Name="Cell00"/>
<Button Name="Cell01"/>
<Button Name="Cell02"/>
<Button Name="Cell10"/>
<Button Name="Cell11"/>
<Button Name="Cell12"/>
<Button Name="Cell20"/>
<Button Name="Cell21"/>
<Button Name="Cell22"/>
<Grid/>
Now for the function that would check for a win, I would have to check all possible combinations like this is in the code behind:
private bool CheckForWin()
{
if((Cell00 == Cell01) && (Cell01 == Cell02) && isNotBlank(Cell02)) return true;
if((Cell10 == Cell11) && (Cell11 == Cell12) && isNotBlank(Cell12)) return true
...
return false; //if none of the win conditions pass
}
This type of code would be extremely cumbersome. I would like to write it instead in a way that lets me check the array with for loops.
I realize that with tic-tac-toe, it is fairly easy to code it using brute force, but this was the first example that came to my head. Other games like Reversi or Go would not work well like this because of either the sheer size or the fact that pieces placed can change other cells than the one they were placed on.
Any help with this would be greatly appreciated.
This is not the correct way to use WPF. WPF is designed to use data binding....creating and manipulating UI elements directly is bad form. There are more posts/discussion/questions about this than you can imagine and I'll leave you to research them for yourself. In the mean time this is how you use WPF "properly":
First use NuGet to add MVVM lite to your project so that you get the ViewModelBase class and create a view model for a single cell:
public class Cell : ViewModelBase
{
private string _Text;
public string Text
{
get { return _Text; }
set { _Text = value; RaisePropertyChanged(() => this.Text); }
}
}
One level up you'll want a main model to encapsulate an array of these, this is where you will typically do all your game logic:
public class MainModel : ViewModelBase
{
private ObservableCollection<Cell> _Cells;
public ObservableCollection<Cell> Cells
{
get { return _Cells; }
set { _Cells = value; RaisePropertyChanged(() => this.Cells); }
}
public MainModel()
{
this.Cells = new ObservableCollection<Cell>(
Enumerable.Range(1, 100)
.Select(i => new Cell { Text = i.ToString() })
);
}
}
Notice that all I'm doing at the moment is creating a 100-element collection of cells. This main view model becomes the one that you assign to your window's data context:
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainModel();
}
Now your XAML controls need to bind to this data. ItemsControl is used to render a collection of elements so use one of those and bind it to your array. You want them displayed in a 2D grid so replace the ItemsPanelTemplate with a WrapPanel. Finally add a DataTemplate for your Cell class so that a button gets drawn for each cell:
<Window.Resources>
<DataTemplate DataType="{x:Type local:Cell}">
<Button Width="32" Height="32" Content="{Binding Text}"/>
</DataTemplate>
</Window.Resources>
<ItemsControl ItemsSource="{Binding Cells}" Width="320" Height="320" HorizontalAlignment="Center" VerticalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
That's how you use WPF. Your logic is stored entirely in the view model and it's completely decoupled from the view. Here's what this particular code displays, it should be pretty self-evident how flexible this code is and easy to change:
That's very possible. Simply declare an array variable :
private Button[] _buttonArray;
populate the array once, maybe in constructor :
_buttonArray = new[] {Cell00, Cell01, .... , Cell22};
And all of the buttons are now accessible through _buttonArray.

Binding resp. DataTemplate confusion

I am still very new and trying my first serious data binding. I have read a lot about how it works, am just struggling with this concrete example. I have tried to read all links I could find on this, but most sources tend to be a bit imprecise at key spots. So here goes:
-My Application generates dynamically a variable 'PlayerList' of type 'List', where 'Player' is a complex object.
-I want to display this in a ListBox via Binding. Obvoiusly, since Player is a complex Object I want to create a DataTemplate for it. So I have something like this in the 'Window1.xaml':
<ListBox
Name="ListBox_Players"
ItemsSource="{Binding Source={StaticResource PlayerListResource}}"
ItemTemplate="{StaticResource PlayerTemplate}">
</ListBox>
and something like this in the 'App.xaml':
<DataTemplate x:Key="PlayerTemplate"> <!-- DataType="{x:Type Player}" -->
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=name}"/>
<TextBlock Text=", "/>
<TextBlock Text="{Binding Path=nrOfTabls}"/>
</StackPanel>
</DataTemplate>
Of course, this template will become more verbose later. So as you see above, I have tried to create a resource for the PlayerList variable, but have not managed yet, i.e., smthn. like this
<src: XXX x:Key="PlayerListResource"/>
where for XXX as I understand it I should enter the class of the Resource variable. I tried
List<Player>, List<src:Player>
etc., but obv. XAML has trouble with the '<,>' characters.
I also have another problem: By not declaring a resource but by direct binding (i.e., in C# writing "ListBox_Players.ItemsSource=PlayerList;") and deleting the 'ItemTemplate' declaration and overwriting the ToString() method of the Player class to output the name of the Player I have managed to see that the binding works (i.e., I get a list of Player names in the ListBox). But then, if I insert the template again, it displays only ','my Template does not work!
The fact that you're getting just commas without anything else suggests to me that either the names of Player members do not match the names in Path= in the DataTemplate (I had this problem at one point), or the relevant Player members are inaccessible.
I just tested what you've shown of your code so far, and it seemed to work fine. The only change I made was change this line:
ItemsSource="{Binding Source={StaticResource PlayerListResource}}"
to this line:
ItemsSource = "{Binding}"
This tells the program that it'll get the ItemsSource at run time.
My Player class was:
class Player {
public string name { get; set; }
public int nrOfTabls { get; set; }
}
and my MainWindow.xaml.cs was:
public partial class MainWindow : Window {
private ObservableCollection<Player> players_;
public MainWindow() {
InitializeComponent();
players_ =new ObservableCollection<Player> () {
new Player() {
name = "Alex",
nrOfTabls = 1,
},
new Player() {
name = "Brett",
nrOfTabls = 2,
},
new Player() {
name="Cindy",
nrOfTabls = 231,
}
};
ListBox_Players.ItemsSource = players_;
}
}

How to create a fast loading wrapping ListBox?

I've made a nice little three-item wide list of tiles that work as switches. It looks something like this:
Looking good huh? Well, I have about 130 of these tiles in a vertically scrolling list, and it takes ages to load. According to the performance analysis tool, each element takes about 18ms to render - which gives me about a 2.3 second rendering time. On the device, it's often twice that time. This wouldn't really be a crisis, but the UI is totally black and unresponsive up until these elements have been drawn.
After some research online, I realized this is because the WrapPanel control from the toolkit doesn't virtualize its items - thus making the GPU render all objects at once (using up a lot of memory in the process).
Now, are there any ways to make this go faster?
XAML:
<ListBox x:Name="ChannelsListBox" Grid.Row="2" Margin="0,40,0,0">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Template>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="ChannelTile" Margin="6,6,6,6" Tap="ChannelTile_Tap">
<!-- context menu code removed -->
<Rectangle Width="136" Height="136" Fill="{StaticResource LightGrayColor}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The ListBox's ItemsSource is set in the codebehind - if you wondered.
Well, if you populate the listbox asynchronously from another thread, you can avoid the unresponsive UI.
EDITED2:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
/* In the xaml code:
<ListBox x:Name="ChannelsListBox" ItemsSource="{Binding ListOfTestClasses}" ...
*/
var vm = new MainPageViewModel();
DataContext = vm;
vm.StartLoadingDataAsync(10000);
}
}
public class MainPageViewModel
{
public ObservableCollection<TestClass> ListOfTestClasses { get; set; }
private BackgroundWorker workerThread;
public MainPageViewModel()
{
ListOfTestClasses = new ObservableCollection<TestClass>();
workerThread = new BackgroundWorker();
workerThread.DoWork += new DoWorkEventHandler((object sender, DoWorkEventArgs e) =>
{
for (int i = 0; i < (int)e.Argument; i++)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
ListOfTestClasses.Add(new TestClass { Text = "Element " + (i + 1) });
});
Thread.Sleep(150);
}
});
}
public void StartLoadingDataAsync(int numberOfElements)
{
workerThread.RunWorkerAsync(numberOfElements);
}
}
public class TestClass
{
public string Text { get; set; }
}
A few ideas which might be helpful:
Find or implement a virtualizing WrapPanel. It's the most appropriate solution, but I don't think I've seen a solid implementation of one yet. But for this purpose, maybe you don't need perfection and can get away with something someone else has already written.
Use a parent virtualizing vertical StackPanel containing horizontal StackPanel children. To do this, you'd need to re-shape your single sequence of data into a shorter sequence of 3-item entries. However, that may not be too hard and should give you most of the benefits of the ideal solution.
Consider implementing "lazy" containers like I did for DeferredLoadListBox. The basic idea is to delay rendering containers until they show up on screen. I have more info and example code here: http://blogs.msdn.com/b/delay/archive/2010/09/08/never-do-today-what-you-can-put-off-till-tomorrow-deferredloadlistbox-and-stackpanel-help-windows-phone-7-lists-scroll-smoothly-and-consistently.aspx

Categories