0

Edit: The marked solution is correct, however if anyone is having similar problems using SQLite avoid calling the database using using as shown in my example as it messes up lazy loading as the context is closed before it can lazy load. To fix this create a new Object as that will cause lazy loading to fully copy the object passed back from the db so either do that in "using" or manually close the db after you have copied.

I have made a simple example to describe the problem

        <Grid>
            <StackPanel>
                <ListView x:Name="People" ItemsSource="{Binding}">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock Text="{Binding Name}"/>
                                <ListView x:Name="PhoneNumbers" ItemsSource="{Binding PhoneNumbers}"/>
                            </StackPanel>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackPanel>
        </Grid>

So I have a ListView bound to an object let's call it Person() this object has a property of type collection that I want to access. I want to bind a list property in this case just a list of strings to x:name="PhoneNumber" how can I do this? I'm setting the ItemSource of the parent ListView in the code behind. I would like to know any information you have on this topic as I have not been able to find a whole lot on the subject read all of the c# docs, searched stack most I was able to find was to use an ObservableList which I tried, it didn't work. Looking for a data dump any information you think could get me moving in the right dirrection would be greatly appreciated as my actual use case is much more complicated than this example.

I'm aware this would be easier using MVVM but for now I want to get a basic prototype up and running without getting in to MVVM. The end goal is to move to MVVM.

Edit : Literally just binding in code behind atm

Simple example VV

    public LoadingWindow()
    {
        InitializeComponent();

        using (var db = new PeopleContext())
        {
            var Test = db.People.ToList();

            
            if (Test != null)
            {
                People.ItemsSource = Test;
            }
        }
    }

Example Class

public class People
{
    public string Name { get; set; } = "";

    // I did read that using an observable list was needed but I tried it and it didn't work
    // I'd prefer not to use an observable list
    public List<string> PhoneNumbers { get; set; } = new List<string>();
}
moderategamer
  • 189
  • 2
  • 10
  • 1. The outer ListView is not bound to a List, but to a single object of type `Person`? 2. the `Name` is bound to the TextBlock correctly but the `PhoneNumbers` does not bound to the inner ListView correctly? – Muhammad Sulaiman Sep 10 '22 at 14:21
  • Sorry the outer list is bound to a list of people using the itemSource in code behind and the inner list bound to the list stored in the individual persons as far as I'm aware itemsSource is correct. This was just a quick example though – moderategamer Sep 10 '22 at 14:33
  • So yes I'm trying to get the inner listview to bind – moderategamer Sep 10 '22 at 14:36
  • your `xaml` looks good, could you please share the code behind? – Muhammad Sulaiman Sep 10 '22 at 14:41
  • Edited post - but I'm literally just binding to the ListView – moderategamer Sep 10 '22 at 14:50
  • If I change the outer List to be bound to the PhoneNumber list the inner bind works fine so I'm definitely doing something wrong – moderategamer Sep 10 '22 at 14:57
  • `People` is the name of the outer list right? can you add the code for `Person` class? – Muhammad Sulaiman Sep 10 '22 at 15:01
  • This is a made up example but I'll write one up – moderategamer Sep 10 '22 at 15:08
  • Added a poorly formatted People class – moderategamer Sep 10 '22 at 15:13
  • there's "People.ItemsSource = Test;", shouldn't it be "PhoneNumbers.ItemsSource = Test;" ? I'm not sure about List<>, but i guess you need to use ObservableCollection<> class – micegan Sep 10 '22 at 15:18
  • `People.ItemsSource = Test;` means your outer list view has `x:Name="People"`, and the example class is of type `Person` not people, add width and height to the inner StackPanel! – Muhammad Sulaiman Sep 10 '22 at 15:18
  • Sorry like I said it's just a made up example for demonstration purposes it is all correct in my actual code that was just a typo making up the demonstration. As far as your first question "shouldn't it be "PhoneNumbers.ItemsSource = Test;" ?" no I'm binding the outer ListView to the person class which has a list PhoneNumbers I'm trying to bind the inner ListView to that property. – moderategamer Sep 10 '22 at 15:22
  • how can you bind the list to person class, you should bind it to the collection – NoName Sep 10 '22 at 15:24
  • I missed the x:name="People" in the demo code that is what I'm binding to (the outer ListView) sorry that's my fault I've edited the initial XAML – moderategamer Sep 10 '22 at 15:26

1 Answers1

1

Probably the question is not clear, but I figured it out. First of all, you should bind your ListView to ObservableCollection or BindingList in order to get UI updated when your collections are changed. The second problem is that you are not using property to bind your list, you are trying to set your ListView's ItemsSource property to the field, which is not possible. You are using this code var Test = DatabaseInfo.ToList(); Test is a field and then you are trying to bind to it, it is clear that it won't work. You should add a property to your MainWindow BindingList<Person>, and then in the MainWindow constructor fill it with information from DataBase.

So I just created a simple project, as I don't have DataBase I filled collections manually.

In MainWindow I have property BindingList<Person>

 public partial class MainWindow : Window
{
    public BindingList<Person> People { get; set; }
    public MainWindow()
    {
        InitializeComponent();

        People = new BindingList<Person>();

        Person person = new Person() { Name = "Jonh" };
        Person person2 = new Person() { Name = "Mike" };
        People.Add(person);
        People.Add(person2);

        PeopleList.ItemsSource = People;
    }
}

Person class is defined like this

public class Person
{
    public BindingList<string> PhoneNumbers { get; set; }
    public string Name { get; set; }
    public Person()
    {
        PhoneNumbers = new BindingList<string>();
        PhoneNumbers.Add("1");
        PhoneNumbers.Add("2");
        PhoneNumbers.Add("3");
        PhoneNumbers.Add("4");
    }
}

I used same XAML, your XAML code doesn't have any problems

<ListView x:Name="PeopleList">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Name}"/>
                    <ListView x:Name="PhoneNumbers" ItemsSource="{Binding PhoneNumbers}"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

Here is result

enter image description here

Just use BindinList<T> or ObservableCollection<T> and it should work.

NoName
  • 181
  • 8
  • Yeah still no luck Could it be because the list in my actual code is a list of objects? In my actual code I am binding to the inner list to the what would be PhoneNumbers list and then binding TextBlocks to that classes properties? I tried just binding to the class and not having a template just allowing the ToString menthod to do it's thing but I still get no value – moderategamer Sep 10 '22 at 15:55
  • Do I need to implement an Interface to allow BindingList to work on a class? I've never used BindingList before – moderategamer Sep 10 '22 at 15:59
  • No, it works without any interface if I get you correct. You can use `ObservableCollection` too, your problem was related to the fact that you were not binding to `property` – NoName Sep 10 '22 at 16:37
  • Sorry can you elaborate on "not Binding to property"? as far as I can tell there is no deference between mine and your code other than mine not using BindingList – moderategamer Sep 10 '22 at 16:52
  • I should add encase it is not clear the outer binding works just fine. I'm just getting no population of the inner listview – moderategamer Sep 10 '22 at 16:53
  • **"as far as I can tell there is no difference between mine and your code other than mine not using BindingList"** there is, beside the fact that I was using BindinList, I was using property while you were using field to set `ItemsSource` of `ListView`. Read [Difference between Field and Property](https://stackoverflow.com/questions/295104/what-is-the-difference-between-a-field-and-a-property) and [Data binding overview](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/?view=netdesktop-6.0). Also, you can check the answer again I edited it – NoName Sep 10 '22 at 17:10
  • I mean I tried with a property and it made no difference. – moderategamer Sep 10 '22 at 17:19
  • Any Other suggestions? I've set it up exactly as you said and it still doesn't work – moderategamer Sep 10 '22 at 19:48
  • I think it must be taking issue that its a custom class – moderategamer Sep 10 '22 at 19:49
  • Sorry to keep messaging but I set the whole thing up with a BindingList of strings and it works fine so it's definitely the custom class it's taking issue with – moderategamer Sep 10 '22 at 20:28
  • In order for UI to get updated, you should use ObservableCollection or BindingList, that's why it doesn't work with the normal list. It is not because of class – NoName Sep 11 '22 at 06:21
  • I'm using a BindingList I also tried observable – moderategamer Sep 11 '22 at 11:24
  • So I fixed it, the problem was with the way I was connecting to the Database using using it was failing to lazy load the classes stored in my property. I removed the using statement and just kept it as a field, no idea if this is leaving my db connection open because there doesn't seem to be a close method – moderategamer Sep 11 '22 at 14:13