Page 1 of 2

How to get Actual Size programmatically based on internal content?

Posted: 06 Jun 2019, 05:51
by digimbyte
I'm looking at dynamic menu's that can be clamped to within screen space
but I can't get the ActualHeight/Width to set the offsets.
I saw in an older thread that this depends on the UI being passed to the renderer first.
but it was never explained the process of doing such.

so I was wondering how I might be able to constrain the dimensions
based on internal content as ActualHeight returns 0?
        Button origin = ((Noesis.Button)sender);
        Point position = origin.PointToScreen(new Point(0f,26f));

        Noesis.StackPanel Menu = new Noesis.StackPanel
        {
            Background = Brushes.Beige,
            MinWidth = 150,
            MaxWidth = 250,
            MinHeight = 12,
            CanVerticallyScroll = true
        };

        for (int i = 0; i < Singularity.random(3, 15); i++)
        {
            Menu.Children.Add(new Button
            {
                Focusable = false,
                Content = Singularity.random(1, 200).ToString(),
                Margin = Thickness.Parse("1")
                //Padding = Thickness.Parse("15,5")
            });
        }
        Debug.Log("HEIGHT: " + Menu.ActualHeight);
        Debug.Log("WIDTH: " + Menu.ActualWidth);
        
        
        position.X = Mathf.Clamp(position.X, 0, Screen.width - Menu.ActualWidth);
        position.Y = Mathf.Clamp(position.Y, 0, Screen.height - Menu.ActualHeight);

Re: How to get Actual Size programmatically based on internal content?

Posted: 08 Jun 2019, 05:29
by digimbyte
I've been working on a data structure to handle the buttons but still, no progress on clamping elements to the view
Image
I've moved code around so it should add to the uiRoot before calling ActualWidth
however, I need some sort of callback to the loaded event
this scopes outside what I'm familiar with in C#

Re: How to get Actual Size programmatically based on internal content?

Posted: 10 Jun 2019, 07:39
by digimbyte
Found a solution, the documentation doesn't give an example.
once it's added to the main UI, you add a .Loaded =+(){}'
DropMenu.Loaded += (object _sender, Noesis.RoutedEventArgs e) =>
        {
            Button origin = ((Noesis.Button)originalSender);
            Point position = origin.PointToScreen(new Point(0f, 26f));
            position.Y = Mathf.Clamp(position.Y, 0, uiRoot.ActualHeight - DropMenu.ActualHeight);
            position.X = Mathf.Clamp(position.X, 0, uiRoot.ActualWidth - DropMenu.ActualWidth);
            DropMenu.Margin = Thickness.Parse(position.X.ToString() + "," + position.Y.ToString() + ",0,0");
        };

Re: How to get Actual Size programmatically based on internal content?

Posted: 10 Jun 2019, 12:20
by sfernandez
Hi, sorry for the late answer.

ActualWidth and ActualHeight properties are calculated during the layout process in the UI Update, so they won't provide meaningful values just after element gets created or its size/position properties has changed. You can force an update by calling element.UpdateLayout(), or as you have done, after creating the element wait until Loaded event is raised.

But in this situation, couldn't you use a simple StackPanel with HorizontalAlignment="Right" and let the system handle the positioning?

And just a suggestion, instead of creating Thickness objects parsing a string, you can construct them like:
DropMenu.Margin = new Thickness(position.X, position.Y, 0, 0);

Re: How to get Actual Size programmatically based on internal content?

Posted: 11 Jun 2019, 01:01
by digimbyte
it actually uses stack panels already, but it's not a child of the initiator, as I am attempting to create menu's like you would in windows application where content needs to overlay other elements.
        Noesis.StackPanel DropMenu = new Noesis.StackPanel
        {
            Background = Brushes.Beige,
            MinWidth = 150,
            MaxWidth = 250,
            MinHeight = 12,
        };
        
        DropMenu.HorizontalAlignment = HorizontalAlignment.Left;
        DropMenu.VerticalAlignment = VerticalAlignment.Top;
        ActiveMenus.Add(DropMenu);
        uiRoot.Children.Add(DropMenu);
most of the information I was going with was based on my findings in the documentation and here in the forums.
it might be good to have both our codes added to the documentation as examples

Re: How to get Actual Size programmatically based on internal content?

Posted: 11 Jun 2019, 14:04
by sfernandez
I am attempting to create menu's like you would in windows application where content needs to overlay other elements.
There are specific controls for that in Noesis, you can define a Menu with MenuItem children to show a popup with options. And it can be dynamically filled by binding the ItemsSource of the Menu and MenuItems with the corresponding data:
<UserControl
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <HierarchicalDataTemplate x:Key="SubItemTemplate" ItemsSource="{Binding MenuItems}">
            <TextBlock Text="{Binding DisplayName}" />
        </HierarchicalDataTemplate>
    </UserControl.Resources>
    <DockPanel>
        <Menu DockPanel.Dock="Top" ItemsSource="{Binding MenuItems}" ItemTemplate="{StaticResource SubItemTemplate}"/>
        <Grid />
    </DockPanel>
</UserControl>
class MenuItemVM
{
  public ObservableCollection<MenuItemVM> MenuItems { get; private set; }
  public string DisplayName { get; private set; }
  
  public MenuItemVM(string name)
  {
    MenuItems = new ObservableCollection<MenuItemVM>();
    DisplayName = name;
  }
}
Is that what you are trying to do?

Re: How to get Actual Size programmatically based on internal content?

Posted: 12 Jun 2019, 01:03
by digimbyte
to an extent, yes. but due to the nature of my project, I can't rely on XAML files as the content needs to change dynamically. either through user customization or live updates
so I'm attempting to do all this mostly in C#

I want to break away from the rigidity of the XAML files and the problems they come with, ie using blend.
and create a middle software that can be fed data objects to generate the GUI on demand.

Re: How to get Actual Size programmatically based on internal content?

Posted: 12 Jun 2019, 11:05
by sfernandez
What I'm trying to say is that you can create a Menu control in code and feed it with a list of items and it will automatically populate and position the menu items for you. There is no need to manually create buttons and calculate positions, that is all already done by the layout system.

Everything that can be done in XAML can be written in code (or it should be, otherwise it is probably because of a bug or something missing in the API).

For example, following my previous code you can write this:
Menu menu = new Menu();
menu.ItemsSource = menuItemsList;
menu.ItemTemplate = (DataTemplate)XamlReader.Parse(
  "<HierarchicalDataTemplate ItemsSource=\"{Binding MenuItems}\">\n" +
  "  <TextBlock Text=\"{Binding DisplayName}\" />\n" +
  "</HierarchicalDataTemplate>");
DockPanel.SetDock(menu, Dock.Top);
DockPanel panel = new DockPanel();
panel.Children.Add(menu);
I want to break away from the rigidity of the XAML files and the problems they come with, ie using blend.
What problems did you find working with Blend? We would like to know if there is something we can improve for future versions.

Re: How to get Actual Size programmatically based on internal content?

Posted: 12 Jun 2019, 13:38
by digimbyte
Originally, I was looking at menu items, but realized that some content I would need in those span outside typical menu entries, such as volume controls and other tools.
so I moved to StackPanels - I will look at menu's again.

as for Blend, it's an overbearing application with tools and widgets that seem convoluted and impractical when you want basic elements on demand.
combine that with the user interface that looks like a broken powerpoint, it doesn't have a smooth workflow or decent user experience.
it also broke several things when attempting to merge and use it with the Unity workflow.
in the end, it wasn't worth it. especially since Noesis supports runtime building, which is perfect.

Ideally, what I want is to be able to create GUI with nested .dot notation, not move vectors and rulers around. it is backwards to what I would want when creating a GUI.
hopefully, when I'm done, I would like to submit my script to the samples so others can look at doing it programmatically

Re: How to get Actual Size programmatically based on internal content?

Posted: 14 Jun 2019, 14:15
by jsantos
hopefully, when I'm done, I would like to submit my script to the samples so others can look at doing it programmatically
That would be awesome!