0

I have this object of class type HouseInfo that contains a list property:

public class HouseInfo
    {
        public string House
        {
            get;
            set;
        }

        public List<String> Details
        {
            get;
            set;

        }

    }
 public List<HouseInfo> HouseInfos { get; set; }

I am successfully binding the House property to main items of combo box using ItemSource property in xaml but can't figure out the binding of Details to their respective submenus.

<ComboBox x:Name="Houses1"
                                  Grid.Row="1"
                                  Grid.Column="4"
                                  ItemsSource="{Binding HouseInfos}"
                                  Padding="0"
                                  DisplayMemberPath="House"
                                  VerticalContentAlignment="Center"
                                  VerticalAlignment="Top"
                                  HorizontalContentAlignment="Stretch"
                                  Margin="0,0,0,2">
</ComboBox>

I tried customizing menuitems in xaml but I get the error "itemsCollection must be empty before using items Source."

How do I get the Details list in each menu item as submenu items?

Any help would be appreciated. Thanks in advance.

Update:

I have bound submenu items as well but they are not visible. I am sure they have bound successfully as it generates submenu items equal to the count of the list inside the details property list of the object. This is the updated xaml for the menu:

 <Menu x:Name="menu"
                              VerticalAlignment="Top"
                              Grid.Row="1"
                              Grid.Column="4"
                              Height="19">
                            <MenuItem ItemsSource="{Binding HouseInfos}"
                                      Padding="0"
                                      Background="#0068FF11"
                                      VerticalAlignment="Top"
                                      RenderTransformOrigin="0.5,0.5"
                                      Height="19"
                                      Width="105">
                                <MenuItem.RenderTransform>
                                    <TransformGroup>
                                        <ScaleTransform />
                                        <SkewTransform />
                                        <RotateTransform />
                                        <TranslateTransform X="0.5" />
                                    </TransformGroup>
                                </MenuItem.RenderTransform>
                                <MenuItem.Header>
                                    <Label x:Name="headerYears"
                                           Margin="0"
                                           Padding="0"
                                           Content="Houses"
                                           Background="#00FF0000"
                                           MaxHeight="18"
                                           UseLayoutRounding="False"
                                           RenderTransformOrigin="0,0"
                                           HorizontalContentAlignment="Center" />
                                </MenuItem.Header>
                                <MenuItem.ItemContainerStyle>
                                    <Style TargetType="{x:Type MenuItem}">
                                        <Setter Property="Header"
                                                Value="{Binding House}" />
                                        <Setter Property="ItemsSource"
                                                Value="{Binding InfoPoints}" />
                                    </Style>
                                </MenuItem.ItemContainerStyle>
                            </MenuItem>
                        </Menu>

Here is the image of menu which is populated but not visible.

Bound but invisible submenu items

  • This is exactly what you want . see this link : https://stackoverflow.com/questions/23941314/wpf-how-can-i-create-menu-and-submenus-using-binding . – Meysam Asadi Feb 07 '21 at 13:37
  • ok, that is close to what I want but I have bound the submenus as well. I just can't understand why they are not visible. Check the Update in the question. – Divyanshu Agrawal Feb 07 '21 at 13:42

2 Answers2

0

Try using the DataSource property of the combobox. You can assign HouseInfos.House1.

What I did was I dynamically assign them to the combobox

comboBox1.DataSource = HouseInfo.House1.Details;
comboBox1.DisplayMember = "HouseDetails";
comboBox1.ValueMember = "HouseDetailsID";

Or you can try something like the above.

0

Use this structure. I matched the names with your own names.

MainWindw.xaml

 <Window x:Class="MyNameSpace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyNameSpace"
        mc:Ignorable="d"
        Title="TestMenu" Height="450" Width="800">
    <DockPanel>
        <Menu DockPanel.Dock="Top" ItemsSource="{Binding MenuItems}">
            <Menu.ItemContainerStyle>
                <Style TargetType="{x:Type MenuItem}">
                    <Setter Property="Command" Value="{Binding Command}" />
                </Style>
            </Menu.ItemContainerStyle>
            <Menu.ItemTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:HouseInfo}" ItemsSource="{Binding Path=Details}">
                    <TextBlock Text="{Binding House}"/>
                </HierarchicalDataTemplate>
            </Menu.ItemTemplate>
        </Menu>
        <Grid>
        </Grid>

      
    </DockPanel>
</Window>

MainWindow.cs

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;

namespace MyNameSpace
{
    /// <summary>
    /// Interaction logic for MainWindw.xaml
    /// </summary>
    public partial class MainWindw : Window
    {
        public List<HouseInfo> MenuItems { get; set; }

        public MainWindw()
        {
            InitializeComponent();

            MenuItems = new List<HouseInfo>();
            HouseInfo houseInfo1 = new HouseInfo();
            houseInfo1.House = "Header A";
            houseInfo1.Details = new List<HouseInfo>() { new HouseInfo() { House = "Header A1" }, new HouseInfo() { House = "Header A2" } };


            HouseInfo houseInfo2 = new HouseInfo();
            houseInfo2.House = "Header B";
            houseInfo2.Details = new List<HouseInfo>() { new HouseInfo() { House = "Header B1" }, new HouseInfo() { House = "Header B2" } };


            MenuItems.Add(houseInfo1);
            MenuItems.Add(houseInfo2);
            DataContext = this;
        }
    }

    public class HouseInfo
    {
        public string House
        {
            get;
            set;
        }
        public List<HouseInfo> Details { get; set; }

        private readonly ICommand _command;
        public HouseInfo()
        {
            _command = new CommandViewModel(Execute);
        }

        public ICommand Command
        {
            get
            {
                return _command;
            }
        }

        private void Execute()
        {
            // (NOTE: In a view model, you normally should not use MessageBox.Show()).
            MessageBox.Show("Clicked at " + House);
        }
    }

    public class CommandViewModel : ICommand
    {
        private readonly Action _action;

        public CommandViewModel(Action action)
        {
            _action = action;
        }

        public void Execute(object o)
        {
            _action();
        }

        public bool CanExecute(object o)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged
        {
            add { }
            remove { }
        }
    }
}

you can gave style to every element with this code

<Menu.ItemContainerStyle>
     <Style TargetType="{x:Type MenuItem}">
          <Setter Property="Command" Value="{Binding Command}" />
     </Style>
</Menu.ItemContainerStyle>

for example add this line to HouseInfo class

public Thickness Margin { get; set; }

and MainWindow.cs

MenuItems = new List<HouseInfo>();
HouseInfo houseInfo1 = new HouseInfo();
houseInfo1.House = "Header A";
houseInfo1.Margin = new Thickness(5);
houseInfo1.Details = new List<HouseInfo>() { new HouseInfo() { House = "Header A1" }, new HouseInfo() { House = "Header A2", Margin=new Thickness(10) } };

and set Style in xaml

<Menu.ItemContainerStyle>
   <Style TargetType="{x:Type MenuItem}">
         <Setter Property="Command" Value="{Binding Command}" />
         <Setter Property="Margin" Value="{Binding Margin}" />
   </Style>
</Menu.ItemContainerStyle>

test:

enter image description here

Meysam Asadi
  • 6,438
  • 3
  • 7
  • 17