Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dropdown Binding automatic updates upon list changes #22

Open
marijneken opened this issue Jul 17, 2018 · 7 comments
Open

Dropdown Binding automatic updates upon list changes #22

marijneken opened this issue Jul 17, 2018 · 7 comments

Comments

@marijneken
Copy link

marijneken commented Jul 17, 2018

In Unity-Weld-Examples, there is one Dropdown example. The example shows how to connect to a simple string[] array in the view model, but that only updates the list once upon initialization.

I'm having a hard time figuring out how to bind to a list so it will automatically update upon changes in that list. The example uses a simple string[] as the type, but I noticed that there are classes like ObservableList and BoundObservableList. So I thought I could maybe use those types of lists instead, but no luck. Simply making the string[] array property a [Binding] and doing a call to OnPropertyChanged("MyList") when the list is changed, seems to have no effect.

I looked at the code of DropdownBinding, but couldn't figure out if and how it could be done. I feel like I'm missing something really obvious here, so that's why I thought it's probably best to ask you.

On a side note: I'm using this to link to items from a database, so I'd like to use the ID of those items as the actual value that is used as the Selection value. I'm pretty sure that could be done by using the "Selection View Model To UI Adapter", "Selection UI To View Model Adapter" and "Options Adapter" settings. So hopefully a solution exists where I could solve both of these "problems" at the same time. Thanks.

@NyxWallace
Copy link

I have the same exact problem, I need to get a collection of user from a database, but if I change the collection after initialization nothing change (I've tryied the above solutions as well before coming here), is there a way to do it?

@marijneken
Copy link
Author

Yes. There's definitely a way, because I figured it out. I'm not at my computer at the moment, but I'll look it up later and write it down.

@NyxWallace
Copy link

Thanks, that would be very kind of you.

@marijneken
Copy link
Author

Sorry, I still intend to write it down, but I've suddenly become super busy. I'll try to find some time soon.

@marijneken
Copy link
Author

OK, so here's how to do it. My example is for a simple list that uses a Vertical Layout Group, but this can be easily adjusted for a Dropdown of course.
image

This is my Hierarchy:
image

The ServerProjectList holds the view model for my list:
image

The simplified code for that is:

using UnityEngine;
using UnityWeld.Binding;

namespace VDT.UnityPlugin.VR
{
    [Binding]
    public class ServerProjectListViewModel : MonoBehaviour
    {
        [Binding]
        public ObservableList<ProjectItemViewModel> ProjectItems { get; private set; }

        public ServerProjectListViewModel()
        {
            // We can't initialize the list directly with an auto property initializer in C# 4. We could do this in C# 6 and up.
            ProjectItems = new ObservableList<ProjectItemViewModel>();
        }

        [Binding]
        public void SelectProject(int projectId)
        {
            // TODO: Do something
        }

        private void OnProjectListResultHandler(object sender, ProjectListResultEventArgs e)
        {
            ProjectItems.Clear();
            foreach (var project in e.Projects)
            {
                ProjectItems.Add(new ProjectItemViewModel(project));
            }
        }

        private void OnEnable()
        {
            FrameworkSettings.Instance.RegisterProjectListHandler(OnProjectListResultHandler);
        }

        private void OnDisable()
        {
            FrameworkSettings.Instance.UnRegisterProjectListHandler(OnProjectListResultHandler);
        }
    }
}

This uses the ObservableList which automatically updates the UI when its contents change.
As you can see, I'm registering a Handler to be used as a callback for when new items are loaded. I then clear the old list and add the new items.

Then the ProjectList has a Vertical Layout Group and also the CollectionBinding component:
image
image

That's where you choose the property to bind to in your View Model. In our case ProjectItems. The Collection templates simply refers to the Project GameObject in our Hierarchy. It contains the following components:
image

The ProjectItemViewModel is pretty straightforward:

using System.ComponentModel;
using UnityWeld.Binding;

namespace VDT.UnityPlugin.VR
{
    [Binding]
    public class ProjectItemViewModel : INotifyPropertyChanged
    {
        [Binding]
        public int ProjectId { get; private set; }

        [Binding]
        public string ProjectName { get; private set; }

        public ProjectItemViewModel(Project project)
        {
            ProjectId = project.ProjectId;
            ProjectName = project.ProjectName;
        }

        /// <summary>
        /// Event to raise when a property's value has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

You can bind the text on your button or dropdown list item to the ProjectName property and you're all set.

I hope this helps. Cheers, Marijn.

@NyxWallace
Copy link

Hi Marijn, thank you for taking the time, but unfortunatly I'm still stuck because the drop down list, as you mention in your initial comment, does not bind to an ObservableList (or at least it doesn't seems to do so). It is also worth mentioning that every other script let me choose the property I'm willing to bind to, but here I have to write down the properties, so I'm not even sure I'm doing it correctly. I think I'll just find a work around using a list.

@marijneken
Copy link
Author

Hmm, I had a quick look at the DropDown. It's been a while since I dealt with it. I now notice that it seems a bit convoluted in its setup. It's not that different from a list, in terms of functionality, so I'm pretty sure you'd be better off building your own dropdown control, because then you have better control over things like data binding. Sorry I couldn't be of me help right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants