elw00d / consoleframework

Cross-platform toolkit for easy development of TUI applications.
http://elw00d.github.io/consoleframework
MIT License
551 stars 64 forks source link

FindChildByName returns null when trying to get a MenuItem #8

Open ktodyruik opened 10 years ago

ktodyruik commented 10 years ago

Hi,

I'm trying to attach an event handler to an exit menu item. FindChildByName<> always returns null when I try to get the menu item.

Program.cs

WindowsHost windowsHost = (WindowsHost) ConsoleApplication.LoadFromXaml("HelloWorld.windows-host.xml", null);
            Window mainWindow = (Window) ConsoleApplication.LoadFromXaml("HelloWorld.main.xml", null);
            windowsHost.Show(mainWindow);
            MenuItem exit = windowsHost.MainMenu.FindChildByName<MenuItem>("exit");
           // exit is null

windows-host.xml

<WindowsHost>
  <WindowsHost.MainMenu>
    <Menu HorizontalAlignment="Stretch">
      <Menu.Items>
        <MenuItem Title="_Application" Type="Submenu" Gesture="Alt+F" Name="application">
          <MenuItem Title="_About" Name="about"/>
          <MenuItem Title="E_xit" TitleRight="Alt+X" Name="exit"/>
        </MenuItem>
      </Menu.Items>
    </Menu>
  </WindowsHost.MainMenu>
</WindowsHost>
elw00d commented 10 years ago

Unfortunately, Menu is constructed using popup window to display menu items. And this popup is displayed as regular window (by calling WindowsHost), so menu items are not direct children of Menu in visual tree. You can try to use commands (see Commands example):

<MenuItem Title="_Run command" TitleRight="Ctrl+R" Gesture="Ctrl+R"
                    Command="{Binding MyCommand, Mode=OneTime}"/>

It is the simpliest way at now.. I'll think about how to get direct instances to objects like this more gracefully.

ktodyruik commented 10 years ago

Thanks. That worked for my exit menu item. Could you show me an example of how to create a window, and then open it from the menu item click binding command? I tried this, but it doesn't seem to work:

 private static void Main(string[] args)
        {
            DataContext dataContext = new DataContext();

            WindowsHost windowsHost = (WindowsHost)ConsoleApplication.LoadFromXaml("HelloWorld.windows-host.xml", dataContext);
            Window timeServiceWindow = (Window)ConsoleApplication.LoadFromXaml("HelloWorld.timeservice.xml", null);

            dataContext.OpenTimeServiceWindowCommand = new RelayCommand(param => windowsHost.Show(timeServiceWindow));

//            windowsHost.Show(timeServiceWindow);
            ConsoleApplication.Instance.Run(windowsHost);
        }

        public class DataContext : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;

            [NotifyPropertyChangedInvocator]
            protected virtual void OnPropertyChanged(string propertyName)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
            }

            public DataContext()
            {
                ExitCommand = new RelayCommand(param => Environment.Exit(0));
            }

            public ICommand ExitCommand { get; set; }
            public ICommand OpenTimeServiceWindowCommand { get; set; }
     }
elw00d commented 10 years ago

Did you use OneTime binding mode to bind OpenTimeServiceWindowCommand ? OneTime binding works only when object is being created from xaml. May be you need OneWay binding ? And it is need to raise PropertyChanged when command will be changed.