This is actually a second follow-up to Correct MVVM format, but I have made different changes.
This is my ViewModel.cs class for my MainPage.xaml:
public partial class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<MenuItem> _back = new ObservableCollection<MenuItem>();
public ObservableCollection<MenuItem> Back
{
get { return _back; }
set { _back = value; }
}
private ObservableCollection<string> _back1 = new ObservableCollection<string>();
public ObservableCollection<string> Back1
{
get { return _back1; }
set { _back1 = value; }
}
private ObservableCollection<MenuItem> _itemList = new ObservableCollection<MenuItem>();
public ObservableCollection<MenuItem> ItemList
{
get { return _itemList; }
set { _itemList = value; }
}
private ObservableCollection<string> _itemTitles = new ObservableCollection<string>();
public ObservableCollection<string> ItemTitles
{
get { return _itemTitles; }
set
{
if (_itemTitles == value) return;
_itemTitles = value;
OnPropertyChanged();
}
}
private string _currentTitle = "Menu 1";
public string CurrentTitle
{
get { return _currentTitle; }
set
{
_currentTitle = value;
OnPropertyChanged();
}
}
private MenuItem _currentItem = new MenuItem("Menu 1", typeof(Menus.Menu1), AvailWSMenu.Menu1);
public MenuItem CurrentItem
{
get { return _currentItem; }
set
{
_currentItem = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public Windows.ApplicationModel.Resources.ResourceLoader resourceFile = new Windows.ApplicationModel.Resources.ResourceLoader();
public ViewModel()
{
ItemList.Add(new MenuItem(resourceFile.GetString("Menu 1"), typeof(Menus.Menu1), AvailWSMenu.Menu1));
ItemList.Add(new MenuItem(resourceFile.GetString("Menu 2"), typeof(Menus.Menu2), AvailWSMenu.Menu2));
ItemList.Add(new MenuItem(resourceFile.GetString("Menu 3"), typeof(Menus.Menu3), AvailWSMenu.Menu3));
ItemList.Add(new MenuItem(resourceFile.GetString("Menu 4"), typeof(Menus.Menu4), AvailWSMenu.Menu4));
ItemTitles = new ObservableCollection<string>(ItemList.Select(x => x.Title));
}
public void SelectionChanged(string newSelection)
{
Back.Insert(0, new MenuItem(newSelection, ItemList[ItemTitles.IndexOf(newSelection)].Page, ItemList[ItemTitles.IndexOf(newSelection)].Menu));
if (newSelection.StartsWith(" ")) return;
ItemList.RemoveAll(_ => _.Title.StartsWith(" "));
ItemTitles.RemoveAll(_ => _.StartsWith(" "));
switch (newSelection)
{
case "Menu 1":
ItemList.Insert(1, (new MenuItem(resourceFile.GetString("Submenu 2"), typeof(Menus.MenuItems.Submenu2), AvailWSMenu.Menu1)));
ItemList.Insert(1, (new MenuItem(resourceFile.GetString("Submenu 1"), typeof(Menus.MenuItems.Submenu1), AvailWSMenu.Menu1)));
ItemTitles.Insert(1, resourceFile.GetString("Submenu 2"));
ItemTitles.Insert(1, resourceFile.GetString("Submenu 1"));
break;
case "Menu 2":
ItemList.Insert(2, (new MenuItem(resourceFile.GetString("Submenu 4"), typeof(Menus.MenuItems.Submenu4), AvailWSMenu.Menu2)));
ItemList.Insert(2, (new MenuItem(resourceFile.GetString("Submenu 3"), typeof(Menus.MenuItems.Submenu3), AvailWSMenu.Menu2)));
ItemTitles.Insert(2, resourceFile.GetString("Submenu 4"));
ItemTitles.Insert(2, resourceFile.GetString("Submenu 3"));
break;
case "Menu 3":
ItemList.Insert(3, (new MenuItem(resourceFile.GetString("Submenu 5"), typeof(Menus.MenuItems.Submenu5), AvailWSMenu.Menu3)));
ItemTitles.Insert(3, resourceFile.GetString("Submenu 5"));
break;
case "Menu 4":
ItemList.Insert(4, (new MenuItem(resourceFile.GetString("Submenu 10"), typeof(Menus.MenuItems.Submenu10), AvailWSMenu.Menu4)));
ItemList.Insert(4, (new MenuItem(resourceFile.GetString("Submenu 9"), typeof(Menus.MenuItems.Submenu9), AvailWSMenu.Menu4)));
ItemList.Insert(4, (new MenuItem(resourceFile.GetString("Submenu 8"), typeof(Menus.MenuItems.Submenu8), AvailWSMenu.Menu4)));
ItemList.Insert(4, (new MenuItem(resourceFile.GetString("Submenu 7"), typeof(Menus.MenuItems.Submenu7), AvailWSMenu.Menu4)));
ItemList.Insert(4, (new MenuItem(resourceFile.GetString("Submenu 6"), typeof(Menus.MenuItems.Submenu6), AvailWSMenu.Menu4)));
ItemTitles.Insert(4, resourceFile.GetString("Submenu 10"));
ItemTitles.Insert(4, resourceFile.GetString("Submenu 9"));
ItemTitles.Insert(4, resourceFile.GetString("Submenu 8"));
ItemTitles.Insert(4, resourceFile.GetString("Submenu 7"));
ItemTitles.Insert(4, resourceFile.GetString("Submenu 6"));
break;
}
}
public void GoBack()
{
if (Back.Count == 1) return;
if (Back[1].Title.StartsWith(" ") && Back[0].Menu != Back[1].Menu)
{
Back.RemoveAt(0);
switch (Back[1].Menu)
{
case AvailWSMenu.Menu1:
CurrentTitle = resourceFile.GetString("Menu 1");
break;
case AvailWSMenu.Menu2:
CurrentTitle = resourceFile.GetString("Menu 2");
break;
case AvailWSMenu.Menu3:
CurrentTitle = resourceFile.GetString("Menu 3");
break;
case AvailWSMenu.Menu4:
CurrentTitle = resourceFile.GetString("Menu 4");
break;
}
}
Back.RemoveAt(0);
CurrentTitle = Back[0].Title;
Back.RemoveAt(0);
}
}
My MenuItem.cs contains two things, an enum AvailMenus
and a class MenuItem
:
public enum AvailMenus
{
Menu1, Menu2, Menu3, Menu4, MenuItem
}
public class MenuItem
{
public MenuItem(string title, Type page, AvailMenus menu)
{
Title = title;
Page = page;
Menu = menu;
}
private string _title = "";
public string Title
{
get { return _title; }
set { _title = value; }
}
private Type _page = null;
public Type Page
{
get { return _page; }
set { _page = value; }
}
private AvailMenus _menu = new AvailMenus();
public AvailMenus Menu
{
get { return _menu; }
set { _menu = value; }
}
}
This is my MainPage.xaml:
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="100" x:Name="TitleRow"/>
<RowDefinition Height="*" x:Name="DataRow"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" x:Name="ItemsColumn"/>
<ColumnDefinition Width="*" x:Name="DataColumn"/>
</Grid.ColumnDefinitions>
<ListBox Background="WhiteSmoke" Name="Items" Grid.Column="0" Grid.RowSpan="2" ItemsSource="{Binding ItemTitles}" SelectionChanged="OnSelectionChanged"
Margin="-2,-2,0,-2" Padding="0,10" SelectedValue="{Binding CurrentTitle, Mode=TwoWay}" />
<Viewbox Name="TitleView" Margin="10" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Column="1">
<TextBlock Name="TitleText" Foreground="Black" Margin="5,10,5,5"
Text="{Binding SelectedValue, ElementName=Items}" />
</Viewbox>
<Border Grid.Column="1" BorderBrush="Black" BorderThickness="0,1,0,0" VerticalAlignment="Bottom" Height="1"/>
<Frame Grid.Column="1" Grid.Row="1" Foreground="Black" FontSize="20" Margin="20,20,0,20" Name="DataFrame" VerticalAlignment="Top" />
</Grid>
<Page.BottomAppBar>
<CommandBar>
<AppBarButton Label="Back" Icon="Back" Click="AppBarButton_Click"/>
</CommandBar>
</Page.BottomAppBar>
This is the code-behind in MainPage.xaml.cs:
public sealed partial class MainPage : Page
{
private ViewModel Data = new ViewModel();
public MainPage()
{
this.InitializeComponent();
this.DataContext = Data;
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
Data.SelectionChanged(Items.SelectedValue.ToString());
DataFrame.Navigate(Data.ItemList[Items.SelectedIndex].Page);
}
private void AppBarButton_Click(object sender, RoutedEventArgs e)
{
Data.GoBack();
}
}
This is the RemoveAll
extension for ObservableCollection
:
public static class ExtensionMethods
{
public static int RemoveAll<T>(this ObservableCollection<T> coll, Func<T, bool> condition)
{
var itemsToRemove = coll.Where(condition).ToList();
foreach (var itemToRemove in itemsToRemove)
{
coll.Remove(itemToRemove);
}
return itemsToRemove.Count;
}
}
The one thing I really dislike is maintaining the two ObservableCollection
s ItemList
and ItemTitles
, but I haven't been able to get it to work any other way. I would like my use of MVVM reviewed in particular, as well as my method of handling navigation and everything else.