Navigation content template selector and Hierarchy binding question.

5 Answers 52 Views
NavigationView (Hamburger Menu) Styling
Psyduck
Top achievements
Rank 4
Bronze
Bronze
Iron
Psyduck asked on 12 May 2021, 05:42 AM | edited on 12 May 2021, 05:44 AM

 

Hello

I've attached an example, and the ContentTemplateSelector will cause a designer exception.
Build and debug works fine.

First. In using navigation I want to control everything by binding in MainWindowViewModel.
Each UserControl is a different screen.
However, the combo box and button are the same.
So, when you move the view, the data should remain the same.

This is actually implemented using RadTabControl.
Tab control does not have a hierarchy, so I want to use navigation.

[TabControl Sample.xaml] : This is automatically set to the datacontext in the window if you do not set the datacontext in the usercontrol.

<telerik:RadTabItem Header="View 1" Width="60" >
    <telerik:RadTabItem.Content>
        <userControl:UserControlView/>
    </telerik:RadTabItem.Content>
</telerik:RadTabItem>

Second. In the current source, Hierarchy 1 and 2 are set to View(UserControlMain - This is not really necessary.).
I want to open only the hierarchy by clicking on the hierarchy. (view maintained, only IsExpanded)

However, if you don't put a View in the selector, an exception will be thrown.
"Must disconnect specific child from current parent Visual before attaching to new parent Visual."
This made it happen when you choose Hierarchy 3.

Images are also attached for easy understanding.

I will be glad for your help.
thank you.

 

5 Answers, 1 is accepted

Sort by
1
Accepted
Dilyan Traykov
Telerik team
answered on 18 May 2021, 11:06 AM

Hello,

Thank you for the updated project and image.

The reason why the bindings do not work as expected is that two separate instances of the MainWindowViewModel class are created and used - one in the Resources collection of the MainWindow (in XAML) and one in the constructor of the window. By making the following modification and ensuring that the MainWindow and the views use the same instance, the bindings start functioning as desired at my end:

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this.Resources["MainWindowViewModel"];
        }

As for the selection of the hierarchy items, I believe you can achieve the desired result by setting the IsSelectable property of these items to False:

<telerik:RadNavigationViewItem IsSelectable="False" Content="Hierarchy 3">

I'm attaching the modified version of the project with these two updates. Please let me know if it now functions as expected or if there's something of importance which I've missed.

Regards,
Dilyan Traykov
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

1
Dilyan Traykov
Telerik team
answered on 14 May 2021, 01:54 PM

Hello Psyduck,

Thank you for the provided images and project.

To resolve your first issue, you can define the MainWindowViewModel as a static resource in the MainWindow and pass this instance as the DataContext of the different templates:

            <local:MainWindowViewModel x:Key="MainWindowViewModel" />

            <DataTemplate x:Key="UserControlMain">
				<local:UserControlMain DataContext="{StaticResource MainWindowViewModel}" />
			</DataTemplate>
			<DataTemplate x:Key="ATemplate">
                <local:UserControlA DataContext="{StaticResource MainWindowViewModel}" />
			</DataTemplate>
			<DataTemplate x:Key="BTemplate">
                <local:UserControlB DataContext="{StaticResource MainWindowViewModel}" />
			</DataTemplate>
			<DataTemplate x:Key="CTemplate">
                <local:UserControlC DataContext="{StaticResource MainWindowViewModel}" />
			</DataTemplate>

As for the exception thrown in the NavigationViewContentTemplateSelector, you need to ensure that a template is returned in each scenario. You can add an additional empty template and use this if you find it possible:

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var navigationItemModel = item as RadNavigationViewItem;

            switch (navigationItemModel.Content)
            {
                case "MainView": return this.UserControlMain;
                case "Hierarchy 1": return this.UserControlMain;
                case "Hierarchy 2": return this.UserControlMain;

                case "UserControrl A": return this.ATemplate;
                case "UserControrl B": return this.BTemplate;
                case "UserControrl C": return this.CTemplate;
                default:
                    return this.EmptyTemplate;
            }
        }

Finally, if you wish to modify the behavior of the items when they are clicked or expanded, you can inherit the class and override its OnClick and OnIsExpandedChanged methods:

    public class CustomNavigationViewItem : RadNavigationViewItem
    {
        protected override void OnIsExpandedChanged()
        {
        }

        protected override void OnClick()
        {
        }
    }

I hope you find this information helpful. For your convenience, I've also attached a modified version of the project which I believe should work as you expect. Please have a look and let me know if I've missed something of importance.

Regards,
Dilyan Traykov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Psyduck
Top achievements
Rank 4
Bronze
Bronze
Iron
answered on 17 May 2021, 01:19 AM | edited on 17 May 2021, 02:53 AM

Hi.

Your example worked perfectly, but my source is not binding.
I reattach the error sample source.

MainWindow still throws a "NullReferenceException" exception was thrown.
It's only a designer crash.

1. The difference is the way MainView creates a StartView before opening it and binds it.
I did the initial binding, but it seems to be initialized continuously when I do the Selector. I'd appreciate it if you check it out.

2. In your source, the hierarchy of navigation items is now linked to UserControlMainView.
I want to keep these as the previous View, not the MainView. (If you click Hierarchy 3 in UC-B-View, UC-B-View will be maintained.)
Is this also possible with a template?

 

Thanks.

 

0
Psyduck
Top achievements
Rank 4
Bronze
Bronze
Iron
answered on 18 May 2021, 12:02 PM

Thank you. This works perfectly the way I want.

But still MainWindow view throws Exception. (Designer crash)
The example sent above is the same. Is there any solution to this?

"NullReferenceException: Object reference not set to an instance of an object."

Dilyan Traykov
Telerik team
commented on 19 May 2021, 02:25 PM

It appears that the "item as RadNavigationViewItem" cast returns null for some reason when executed by the designer. What I can suggest is to add an extra null-check in the NavigationViewContentTemplateSelector and if this cast does return null, to return the default UserControlMain template. Please  let me know if this works for you.
Psyduck
Top achievements
Rank 4
Bronze
Bronze
Iron
commented on 20 May 2021, 01:24 AM

Yes I solved this. However, in the process of solving, in the case of null, I created an EmptyViewTemplate to solve it. So there is EmptyView.xaml, can you delete it and simplify it?
Dilyan Traykov
Telerik team
commented on 21 May 2021, 02:28 PM

At my end, the exception is also resolved by returning null. Please let me know if this works for you.
0
Psyduck
Top achievements
Rank 4
Bronze
Bronze
Iron
answered on 24 May 2021, 01:19 AM

Hello.

 

Null-checked to avoid null exceptions. And if that doesn't apply, you want an empty view or previous view.

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if (item is Telerik.Windows.Controls.RadNavigationViewItem navigationItemModel)
            {
                switch (navigationItemModel.Content)
                {
                    case "MainView": return this.UserControlMain;
                    case "UserControrl A": return this.ATemplate;
                    case "UserControrl B": return this.BTemplate;
                    case "UserControrl C": return this.CTemplate;
                    default:
                        return this.EmptyViewTemplate;
                }
            }
            else
            {
                return this.EmptyViewTemplate;
            }
        }

I created EmptView.xaml and used return.

 

I want to simplify this. Is emptyview.xaml absolutely necessary?

 

Designer crashes if you put 'null' in EmptyViewTemplate.

"Must disconnect specific child from current parent Visual before attaching to new parent Visual."

 

I am asking for a solution to this.

 

Thanks.

Dilyan Traykov
Telerik team
commented on 26 May 2021, 08:58 AM

At my end, returning null both in the switch statement and in the else block does not result in any exceptions either during runtime or in the designer. I'm using Visual Studio 16.9.4.

Nonetheless, if you do expect the default case of the switch statement to be hit, you can define the EmptyViewTemplate property as follows and delete the .xaml and .xaml.cs files:

public DataTemplate EmptyViewTemplate = new DataTemplate();

Please let me know if this works for you.

Psyduck
Top achievements
Rank 4
Bronze
Bronze
Iron
commented on 26 May 2021, 09:48 AM | edited

I also use Visual Studio 16.9.4. However, returning null will cause the designer to crash.

Simply use the EmptyViewtemplate in the way you suggested and it works fine.

When EmptyView returns, does it appear as a blank screen?
Thanks.
Dilyan Traykov
Telerik team
commented on 28 May 2021, 09:13 AM

Indeed, when an empty DataTemplate is returned, the observed view is empty at my end. You can, however, add elements to this template in code as shown in this article.
Tags
NavigationView (Hamburger Menu) Styling
Asked by
Psyduck
Top achievements
Rank 4
Bronze
Bronze
Iron
Answers by
Dilyan Traykov
Telerik team
Psyduck
Top achievements
Rank 4
Bronze
Bronze
Iron
Share this question
or