public VVPropEditor SetProperty(ViewVariablesBlobMembers.MemberData member)
        {
            NameLabel.Text = member.Name;
            var type = Type.GetType(member.Type);

            _bottomLabel.Text = $"Type: {member.TypePretty}";
            VVPropEditor editor;

            if (type == null || !_robustSerializer.CanSerialize(type))
            {
                // Type is server-side only.
                // Info whether it's reference or value type can be figured out from the sent value.
                if (type?.IsValueType == true || member.Value is ViewVariablesBlobMembers.ServerValueTypeToken)
                {
                    // Value type, just display it stringified read-only.
                    editor = new VVPropEditorDummy();
                }
                else
                {
                    // Has to be a reference type at this point.
                    DebugTools.Assert(member.Value is ViewVariablesBlobMembers.ReferenceToken || member.Value == null || type?.IsClass == true || type?.IsInterface == true);
                    editor = _viewVariablesManager.PropertyFor(type ?? typeof(object));
                }
            }
            else
            {
                editor = _viewVariablesManager.PropertyFor(type);
            }

            var view = editor.Initialize(member.Value, !member.Editable);

            if (!view.HorizontalExpand)
            {
                NameLabel.HorizontalExpand = true;
            }

            NameLabel.MinSize = new Vector2(150, 0);
            TopContainer.AddChild(view);

            /*
             * _beingEdited = obj;
             * _editedProperty = propertyInfo;
             * DebugTools.Assert(propertyInfo.DeclaringType != null);
             * DebugTools.Assert(propertyInfo.DeclaringType.IsInstanceOfType(obj));
             *
             * var attr = propertyInfo.GetCustomAttribute<ViewVariablesAttribute>();
             * DebugTools.Assert(attr != null);
             * NameLabel.Text = propertyInfo.Name;
             *
             * _bottomLabel.Text = $"Type: {propertyInfo.PropertyType.FullName}";
             *
             * var editor = vvm.PropertyFor(propertyInfo.PropertyType);
             * var value = propertyInfo.GetValue(obj);
             *
             * var view = editor.Initialize(value, attr.Access != VVAccess.ReadWrite);
             * if (view.SizeFlagsHorizontal != SizeFlags.FillExpand)
             * {
             *  NameLabel.HorizontalExpand = true;
             * }
             * NameLabel.MinSize = new Vector2(150, 0);
             * TopContainer.AddChild(view);
             * editor.OnValueChanged += v => { propertyInfo.SetValue(obj, v); };
             */
            return(editor);
        }
        private async Task _moveToPage(int page)
        {
            // TODO: Network overhead optimization potential:
            // Right now, (in NETWORK mode) if I request page 5, it has to cache all 5 pages,
            // now the server obviously (enumerator and all that) has to TOO, but whatever.
            // The waste is that all pages are also SENT, even though we only really care about the fifth at the moment.
            // Because the cache can't have holes (and also the network system is too simplistic at the moment,
            // if you do do a by-page pull and you're way too far along,
            // you'll just get 0 elements which doesn't tell you where it ended but that's kinda necessary.
            if (page < 0)
            {
                page = 0;
            }

            if (page > HighestKnownPage || (!_ended && page == HighestKnownPage))
            {
                if (_ended)
                {
                    // The requested page is higher than the highest page we have (and we know this because the enumerator ended).
                    page = HighestKnownPage;
                }
                else
                {
                    // The page is higher than the highest page we have, but the enumerator hasn't ended yet so that might be valid.
                    // Gotta get more data.
                    await _cacheTo((page + 1) *ElementsPerPage);

                    if (page > HighestKnownPage)
                    {
                        // We tried, but the enumerator ended before we reached our goal.
                        // Oh well.
                        DebugTools.Assert(_ended);
                        page = HighestKnownPage;
                    }
                }
            }

            _elementsVBox.DisposeAllChildren();

            for (var i = page * ElementsPerPage; i < ElementsPerPage * (page + 1) && i < _cache.Count; i++)
            {
                var          element = _cache[i];
                VVPropEditor editor;
                if (element == null)
                {
                    editor = new VVPropEditorDummy();
                }
                else
                {
                    var type = element.GetType();
                    editor = Instance.ViewVariablesManager.PropertyFor(type);
                }

                var control = editor.Initialize(element, true);
                if (_networked)
                {
                    var selectorChain = new object[] { new ViewVariablesEnumerableIndexSelector(i) };
                    editor.WireNetworkSelector(Instance.Session !.SessionId, selectorChain);
                }

                _elementsVBox.AddChild(control);
            }

            _page = page;

            _updateControls();
        }