0

WPF/VC++ (C++/cx) - Visual Studio 2013

So I have a ListBox thats populated with a UserControl I've created. Every time the page changes the data is lost, which is unfortunate. So I have the option of loading the data into the ListBox every time the page is loaded or passing the data around from page to page. They each have their own advantage and disadvantage but is there a practice that is preferred?

I suppose the things to think about would be how many of the UserControls are in the ListBox, which could be a large amount (large being 10000+), and how the data is stored. For now I'm storing the data in a AVLTree, mostly for the organization so that sorting doesn't need to be done. There's only 10 pages, 6 of which would normally be navigated to (4 of them being pages that are menus that are rarely used or only used once) so the data wouldn't have to be passed from page to page often. The size of each data node is only about ~1mb, so not very large but large enough to make a difference as you start getting past 10000 entries (which could be considered a rare circumstance).

I come from game programming so speed and efficiency is a primary goal.

Yes, it is a subjective question, however it is possible for there to be a preferred method among professionals or the general programming community.

user3164339
  • 165
  • 14
  • `Every time the page changes the data is lost, which is unfortunate.` - that's because you're probably putting the responsibility of `storing the Data` (in terms of in-memory storage) into the UI, where it does not belong. Create a proper ViewModel and all your problems will magically be solved. BTW post your current code and XAML. – Federico Berasategui Jan 22 '14 at 22:15
  • `I suppose the things to think about would be how many of the UserControls are in the ListBox` - again, UI is NOT data. You don't care about "UserControls in the ListBox" in WPF, because built-in UI Virtualization does the job of creating only the relevant instances of UI elements according to the available `visible` area on screen, leaving "scrolled-out" items out of the equation. Again, post your current code and a screenshot of what you need and I can tell you the proper way to do it in WPF. – Federico Berasategui Jan 22 '14 at 22:18
  • You should use DataBinding, instead of manually putting stuff into the UI. Again, post your current code and XAML and a screenshot of what you need. – Federico Berasategui Jan 22 '14 at 22:23
  • @HighCore when I said "data lost" I only meant that the ListBox was no longer populated, my AVLTree is still holding the data. If thats what you meant anyway. I can't post my code (not allowed to), I could create a 'dummy project' and recreate whats happening but it would have to wait till I leave work and get home. As for the DataBinding are you suggesting binding the ListBox to my AVLTree(I created this in just a .cpp/.h file)? – user3164339 Jan 22 '14 at 22:30
  • Yes, I have no knowledge of C++ at all. WPF only supports DataBinding to .Net objects implementing the `INotifyPropertyChanged` interface. I suggest you leave the C++ stuff for whatever lower-level operations you need, and use C# or VB.Net to create the WPF UI and application-level logic (such as ViewModels and the like) – Federico Berasategui Jan 22 '14 at 22:33
  • the reasoning for using the AVLTree was to avoid having to use SQL as connections and data transfers are expensive, this was a solution that required no connections and was fast for few or many data 'objects'. I hope my c++ background isn't confusing terminology here =/, I apologize if that's the case. – user3164339 Jan 22 '14 at 22:36
  • @HighCore but either way I suppose my question was more of wondering the best approach as to when to populate a ListBox from a datastructure. Or are you saying I shouldn't have to populate the ListBox every time the page is changed and returned to? – user3164339 Jan 22 '14 at 22:39
  • 2
    No, there's no such thing as "populate a ListBox" in WPF. There's only `DataBinding` and `INotifyPropertyChanged`.That's the WPF way, anything else results in a bunch of useless unneeded code. – Federico Berasategui Jan 22 '14 at 23:14
  • 1
    It sounds like you need to educate yourself on proper MVVM approach. It'll take you hours to get accustomed to it , especially if you're from game programming but believe me, it's worth it. Here's an introduction straight from Microsoft: http://www.youtube.com/watch?v=BClf7GZR0DQ There's tons of tutorials online. Good luck! – michal.ciurus Jan 23 '14 at 07:51

1 Answers1

7

Without any more background information, nor details about what you're doing (since you can't post any code or screenshots), I can only tell you what's the basic idea behind The WPF Mentality.

WPF is really different from pretty much any other UI frameworks I've heard of, in the sense that it is really intended to be used for Data-Centric development.

From the ground up, WPF is largely based on DataBinding. This eliminates in like 95% the need to do any manipulations of the UI via procedural code.

As a simple example, say you have a Person class which contains string LastName and string FirstName properties:

public class Person
{
    public string LastName {get;set;}
    public string FirstName {get;set;}
}

Instead of passing data values back and forth to the UI by writing procedural code-behind like this:

//Traditional approach, Don't use this in WPF.
this.txtLastName.Text = person.LastName;
this.txtFirstName.Text = person.FirstName;
//...
person.LastName = this.txtLastName.Text;
person.FirstName = this.txtFirstName.Text;

you simply define a DataBinding in XAML, declaratively:

<TextBox Text="{Binding LastName}"/>
<TextBox Text="{Binding FirstName}"/>

and then set the UI's DataContext to a relevant instance of data:

//Window constructor example
public MainWindow()
{
    InitializeComponent();
    DataContext = new Person();
}

This approach has the following advantages:

  • it clearly Separates UI from Data, allowing a huge amount of scalability due to the independence of these layers. You can put literally ANYTHING in the UI without having to change a single line of code from your application logic / business logic.
  • It reduces boilerplate because WPF takes care of passing data In Both Directions (Data <=> UI).
  • It allows for a property-based approach (as opposed to an event-based one). For example, there is no need for things like handling the TextBox.TextChanged event. WPF takes care of passing the Text value from the TextBoxes in the example to the underlying Data Object when needed.
  • It removes the need to navigate the Visual Tree. The WPF Visual Tree is a really complex structure, which has complex state changes and complex transitions and a complex lifecycle. You really Don't want to have to deal with that in order to, say, "populate a couple of TextBoxes".
  • When dealing with Collections, it helps leverage WPF's UI Virtualization capabilities in a natural way (you don't actually have to do anything it's enabled by default). This causes a Huge Performance Gain both in terms of execution time and memory consumption.
  • Last but not least, it allows for a Declarative approach, as opposed to the traditional Imperative one. You simply Define your data, then you write your business logic (as usual in an imperative form), then Define the UI and it's relations to the data via DataBinding.

This basic concept applies to EVERYTHING in WPF.

With ListBoxes, ComboBoxes, Menus, TabControls, DataGrids, and ALL ItemsControls it's exactly the same:

You don't "populate a ListBox with UserControls", instead:

  • you create a proper ViewModel which contains an IEnumerable<T> which holds your data items. The ObservableCollection<T> is preferred because WPF listens to it's CollectionChanged event and updates the UI accordingly when items are added/removed from the collection:

    public class MyViewModel
    {
        public ObservableCollection<Person> People {get;set;}
    
        //Constructor
        public MyViewModel()
        {
           People = new ObservableCollection<Person>();
    
           //populate the collection here...
        }
    }
    
  • Then you Define the ListBox In XAML and use WPF's Data Templating capabilities to Define how the UI will look like for each item:

    <ListBox ItemsSource="{Binding People}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBox Text="{Binding LastName}"/>
                    <TextBox Text="{Binding FirstName}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox> 
    

    Note: It's the same if you want to use a UserControl in there instead:

            <DataTemplate>
                <my:MyUserControl/>
            </DataTemplate>
    
  • And finally set the UI's DataContext to an instance of the ViewModel:

    //Window Constructor
    public MainWindow()
    {
         InitializeComponent();
         DataContext = new MyViewModel();
    }
    

Note: I mentioned the INotifyPropertyChanged interface in the comments. this interface must be implemented by your Data Items or ViewModels in order to support Two-way Binding properly. Otherwise WPF has no way to "know" when a specific property (such as LastName) is changed and update the UI accordingly. I consider that topic to be out of the scope of this answer and therefore I won't get into it. You can read the linked material, and there is also plenty of material in the Web about it.

As I already mentioned, I have no experience at all in C++, therefore all these examples are in C#. Remember I also mentioned WPF only supports databinding to .Net Objects, and I don't think it supports lower-level in-memory structures such as the ones you may construct in C++.

My suggestion is that you use C# for the upper-level UI-facing part of your software, while leaving C++ for any lower-level operations you might need.

I strongly suggest reading thru the material linked in this post, most importantly Rachel's WPF Mentality and the ItemsControl-related material.

Community
  • 1
  • 1
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • Isn't this processor intensive? I mean, if the UI itself and it's controls are listening at all times for data changes from it's bindings... – Malavos Feb 05 '14 at 16:59
  • 1
    @HugoRocha no, using this technique, WPF only creates the UI elements for items that are visible on screen (due to Scrolling). This results in an [enormous performance gain](http://www.youtube.com/watch?v=D3Y6DnFpHCA). See [UI Virtualizaton](http://www.wpftutorial.net/Virtualization.html). Also see [MSDN](http://msdn.microsoft.com/en-us/library/cc716879(v=vs.110).aspx#Displaying). – Federico Berasategui Feb 05 '14 at 17:03