2
\$\begingroup\$

I am able to save my GridView layout by storing a string representation of the items in the ItemsSource. I then load that string representation from the SettingsService and set the index of the items accordingly.

The layout is changed by drag/dropping items in the GridView. Here is the code-behind:

private void MainGridView_OnDrop(object sender, DragEventArgs e)
{
    var grid = e.OriginalSource as GridView;
    var items = grid?.ItemsSource as ObservableCollection<AppPage>;

    if (items != null)
    {
        var layout = "";

        // save settings
        foreach (var p in items)
        {
            p.PageIndex = items.IndexOf(p);
            // serialize pagename and pageindex
            layout += $"{p.PageName},{p.PageIndex}|";
        }
        _settings.MainMenuLayout = layout;
    }
}

Then when I load the application, I check for the MainMenuLayout setting and parse it out like so:

public void LoadMainMenu()
{
    var pages = new ObservableCollection<AppPage>
    {
        new AppPage("Payees", "ms-appx:///Assets/payee-180.png", typeof(Views.PayeesPage)),
        new AppPage("Bills", "ms-appx:///Assets/invoice-180.png", typeof(Views.InvoicesPage)),
        new AppPage("Payments", "ms-appx:///Assets/envelope-180.png", typeof(Views.PaymentsPage)),
        new AppPage("Checkbook", "ms-appx:///Assets/checkbook-180.png", typeof(Views.CheckbookPage)),
        new AppPage("Receipts", "ms-appx:///Assets/receipt-180.png", null),
        new AppPage("Categories", "ms-appx:///Assets/categories-180.png", typeof(Views.CategoriesPage)),
        new AppPage("Accounts", "ms-appx:///Assets/bank-180.png", typeof(Views.AccountsPage)),
        new AppPage("Budget", "ms-appx:///Assets/budget-180.png", null),
        new AppPage("Contacts", "ms-appx:///Assets/contacts-180.png", typeof(Views.ContactsPage)),
        new AppPage("Reports", "ms-appx:///Assets/charts-180.png", typeof(Views.ReportsPage)),
        new AppPage("Test", "ms-appx:///Assets/beaker-180.png", typeof(Views.TestPage)),
    };

    var layout = _settings.MainMenuLayout;
    if (!string.IsNullOrEmpty(layout))
    {
        // split on |
        var pagesSplit = layout.Split('|');

        foreach (var p in pagesSplit)
        {
            // then split on ,
            if (p.Contains(","))
            {
                var pageInfo = p.Split(',');
                var cur = pages.First(page => page.PageName == pageInfo[0]);
                cur.PageIndex = int.Parse(pageInfo[1]);
            }
        }
    }

    // sort based on index
    AppPages = new ObservableCollection<AppPage>(pages.OrderBy(p => p.PageIndex));
}

Is there a better way to serialize/deserialize the layout? I don't want to store the entire AppPage objects for every item, as there are additional properties that are unrelated to the layout.

\$\endgroup\$
  • \$\begingroup\$ What UI framework is this? WPF? \$\endgroup\$ – svick Jun 8 '16 at 20:28
  • \$\begingroup\$ "I don't want to store the entire AppPage objects" Is there a reason why you don't create a tiny custom object containing only the data you want, and serialize that? \$\endgroup\$ – svick Jun 8 '16 at 20:32
  • \$\begingroup\$ @svick It is a UWP project based on Template 10. I suppose I could create a new class with only the relevant information to be serialized... thanks for the recommendation :) \$\endgroup\$ – dub stylee Jun 8 '16 at 21:01
  • \$\begingroup\$ I can post the XAML for the GridView as well if that would help at all, but I think it isn't really relevant to the C# code. \$\endgroup\$ – dub stylee Jun 8 '16 at 21:02
1
\$\begingroup\$

At the recommendation of @svick, I decided to serialize the objects themselves. Rather than creating a custom object/stub, I just added [JsonIgnore] attribute to the properties that I did not want to serialize.

Here is the new code for saving the layout:

private void MainGridView_OnDrop(object sender, DragEventArgs e)
{
    var grid = e.OriginalSource as GridView;
    var items = grid?.ItemsSource as ObservableCollection<AppPage>;

    if (items != null)
    {
        foreach (var p in items)
        {
            p.PageIndex = items.IndexOf(p);
        }
        // serialize items
        var layout = JsonConvert.SerializeObject(items);
        _settings.MainMenuLayout = layout;
    }
}

Then I was able to simplify reading the layout from settings like so:

var layout = _settings.MainMenuLayout;
if (!string.IsNullOrEmpty(layout))
{
    var pageStubs = JsonConvert.DeserializeObject<ObservableCollection<AppPage>>(layout);

    foreach (var p in pageStubs)
    {
        var cur = pages.First(page => page.PageName == p.PageName);
        cur.PageIndex = p.PageIndex;
    }
    // sort based on index
    AppPages = new ObservableCollection<AppPage>(pages.OrderBy(p => p.PageIndex));
}
else
{
    AppPages = pages;
}

The only properties of AppPage that get serialized are the PageName and PageIndex, which are the only properties used for this process.

Any further improvements are always welcome!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.