Matthias Herrmann
Matthias Herrmann

Reputation: 2790

Windows Universal Implementing Custom SplitView Issues

I'm trying to implement a SplitView Menue with the Hamburger Button on the bottom. In the Designer powered by VisualStudio it is looking like this: enter image description here

The xaml code is that:

<Page.Resources>
        <ValueConverters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
        <vm:ShellViewModel x:Key="ShellVM"/>
    </Page.Resources>
    <Page.DataContext>
        <Binding Source="{StaticResource ShellVM}"/>
    </Page.DataContext>
    <Grid Background="Transparent">
        <SplitView x:Name="SplitView" IsPaneOpen="True" PaneBackground="Gray" Content="{Binding}" DisplayMode="Inline" VerticalAlignment="Bottom" Margin="0,0,0,40" Width="200" HorizontalAlignment="Left">
            <SplitView.Pane>
                <ListView ItemsSource="{Binding MenueButtons}" Height="Auto">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal" Height="Auto">
                                <Grid Width="8" Background="Yellow"  HorizontalAlignment="Left"  Height="20" Margin="-15,4,0,0" Visibility="{Binding Highlighted, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                                <RadioButton FontFamily="Segoe MDL2 Assets"  Style="{StaticResource TextBlockButtonStyle}"  Content="{Binding SymbolIndex}"  Margin="-10,0,14,0"/>
                                <TextBlock Text="{Binding Description}" Margin="-10,5,4,0"/>
                            </StackPanel>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </SplitView.Pane>
        </SplitView>
        <Button x:Name="HamburgerButton" FontFamily="Segoe MDL2 Assets" Content="&#xE700;" HorizontalAlignment="Left" VerticalAlignment="Bottom" Height="40" Foreground="White" FontSize="20"
            Width="50"  Background="Green"/>
    </Grid>

As you can see I'm Binding the ListView Items to an ObservableCollection of type MenueButtons.

Now I'm trying to nest the Frame in the SplitView Content in App.xaml.cs like this:

 protected override void OnLaunched(LaunchActivatedEventArgs e)
        {

            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                var shell = Window.Current.Content as Shell;
                rootFrame = null;
                if (shell == null)
                {
                    shell = new Shell();
                    if (rootFrame == null)
                    {
                        rootFrame = new Frame();
                        rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];

                        rootFrame.NavigationFailed += OnNavigationFailed;

                        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                        {
                        }
                    }

                    shell.DataContext = rootFrame;

                    Window.Current.Content = shell;
                }
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

The code behind Shell.xaml.cs is empty because I'm using the MVVM pattern. But here is the code from the ShellViewModel:

   public class ShellViewModel:INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members
    private ObservableCollection<Models.SplitView.MenueButton>  _menueButtons;

    public ObservableCollection<Models.SplitView.MenueButton> MenueButtons
    {
        get { return _menueButtons; }
        set { _menueButtons = value; OnPropertyChanged("MenueButtons"); }
    }
    #endregion INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public ShellViewModel()
    {
        MenueButtons = new ObservableCollection<Models.SplitView.MenueButton>();
        MenueButtons.Add(new Models.SplitView.MenueButton { Description = "Statistic", SymbolIndex = "\uEA40" });
        MenueButtons.Add(new Models.SplitView.MenueButton { Description = "Settings", SymbolIndex = "\uE713" });
        MenueButtons.Add(new Models.SplitView.MenueButton { Description = "Home", SymbolIndex = " \uE80F", Highlighted = true });

    }
}

Now to the Issues I'm having:

The binding error:

Error: BindingExpression path error: 'MenueButtons' property not found on 'Windows.UI.Xaml.Controls.Frame'. BindingExpression: Path='MenueButtons' DataItem='Windows.UI.Xaml.Controls.Frame'; target element is 'Windows.UI.Xaml.Controls.ListView' (Name='null'); target property is 'ItemsSource' (type 'Object')

And I think because the SplitView is so small the nested frame won't use the whole screen width and height.

Further Information: The ShellViewModel.cs is containing the ObservableCollection. After launching the App I can only see the green hamburger menue button.

How can I fix this errors?

Upvotes: 0

Views: 439

Answers (1)

Jerin
Jerin

Reputation: 4239

There were two problems in your code.
1) Binding of Splitview Content
2) Defined Splitview Width

Now for first major problem you are using ShellViewModel as the dataContext for binding but inside your App.xaml you are initializing datacontext to null frame of rootFrame. The workaround fix would be keeping binding to ShellViewmodel and passing frames.

 protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            var shell = Window.Current.Content as Shell;
            if (rootFrame == null)
            {
                rootFrame = null;
                if (shell == null)
                {

                    if (rootFrame == null)
                    {
                        rootFrame = new Frame();
                        rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];

                        rootFrame.NavigationFailed += OnNavigationFailed;

                        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                        {
                        }
                    }

                    //shell.NewFrame = rootFrame;
                    shell = new Shell(rootFrame);
                    Window.Current.Content = shell;
                }
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

And shell code behind would become

public Shell(Frame frame)
        {
            this.InitializeComponent();
            SplitViewNew.Content = frame;   //this is SplitviewName      
        }

Now Width="200" defines complete Splitview width frame and overlay. I am guessing you intended to use OpenPaneLength="200"
Shell view

<Page.DataContext>
        <vm:ShellViewModel/>
    </Page.DataContext>
    <Grid Background="Transparent">
        <SplitView x:Name="SplitViewNew" IsPaneOpen="True" PaneBackground="Gray"  DisplayMode="Inline" VerticalAlignment="Bottom" Margin="0,0,0,40"  HorizontalAlignment="Left">
            <SplitView.Pane>
                <Grid>
                    <ListView ItemsSource="{Binding MenueButtons}" Height="Auto">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal" Height="Auto">
                                    <Grid Width="8" Background="Yellow"  HorizontalAlignment="Left"  Height="20" Margin="-15,4,0,0" />
                                    <RadioButton FontFamily="Segoe MDL2 Assets"  Style="{StaticResource TextBlockButtonStyle}"  Content="{Binding SymbolIndex}"  Margin="-10,0,14,0"/>
                                    <TextBlock Text="{Binding Description}" Foreground="White" Margin="-10,5,4,0"/>
                                </StackPanel>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </Grid>
            </SplitView.Pane>          
        </SplitView>
        <Button x:Name="HamburgerButton" FontFamily="Segoe MDL2 Assets" Content="&#xE700;" HorizontalAlignment="Left" VerticalAlignment="Bottom" Height="40" Foreground="White" FontSize="20"
            Width="50"  Background="Green"/>
    </Grid>
</Page>

I am uploading Workable Sample so that its easier to see it in working condition. You can now easily make changes if you want to remove code behind completely.

Upvotes: 1

Related Questions