Change ColumnCount based on window size

Hi,

I just started using fuse tools and it had been very easy until I got stuck with the following:

I want to create a new class using StackPanel that can change the number of columns depending on the window size, so I wrote a code like this:

<StackPanel ux:Class="newClass" ux:Name="test" >
    <ColumnLayout ux:Name="cols" ColumnCount="3"/>
    <WhileWindowSize GreaterThan="200,200">
        <Change cols.ColumnCount="1"/>
    </WhileWindowSize>
    <WhileWindowSize GreaterThan="400,400">
        <Change cols.ColumnCount="2"/>
     </WhileWindowSize>
</StackPanel>

And it works pretty fine, but the problem is that I would like to be able pass the number of columns as a property to my newClass, so I tried something like

<StackPanel ux:Class="newClass" ux:Name="test" >
    <float4 ux:Property="SmallSize"/>
    <float4 ux:Property="BigSize"/>
    <ColumnLayout ux:Name="cols" ColumnCount="5"/>
    <WhileWindowSize GreaterThan="0,0">
        <Change cols.ColumnCount="{Property test.SmallSize}"/>
    </WhileWindowSize>
    <WhileWindowSize GreaterThan="400,400">
        <Change cols.ColumnCount="{Property test.BigSize}"/>
     </WhileWindowSize>
</StackPanel>

But unfortunately It does not work because it raises an error saying: ‘Cannot parse ‘{Property test.SmallSize}’ as ‘int’: ‘Input string was not in a correct format.’

It seems like the ColumnCount property was not thought to receive a value from a property.

Any idea on how to solve this?

Regards, Edzon

Hi!

ColumnCount is of type int, so your properties must also be declared as such:

<int ux:Property="SmallSize"/>
<int ux:Property="BigSize"/>

Oh, sorry, there is also one more bug here.

The generic properties like Change does not currently (as of 0.9.11) support value bindings.

We have an issue on file for this and will report back in this thread when it is fixed. Thanks for reporting, and thanks for your patience.

Thanks Anders!

In the meantime, I decided to create my own class using uno. Unfortunately, I have not been able to make it work and I do not know if it is because something is missing on my code or because here we have another bug.

First let me give a little bit of context of why I want to be able to change the number of columns based on the window size. I have been developing mobile apps for a long time using the responsive design approach and I think this is a really easy way to avoid creating as many versions of the app as different sizes of devices you are targeting. Of course, assuming that you want to be able to change the layout of the UI depending on the viewport size.

I would like to be able to change the number of columns based on 5 different sizes (xs – extra small, sm – small, md – medium, lg – large and xl – extra large), so I created this class:

using Uno;
using Uno.Collections;
using Fuse;
using Fuse.Controls;
sealed class RespPanelColumnCountProperty: Uno.UX.Property<int>
{
    Fuse.Layouts.ColumnLayout _obj;
    public RespPanelColumnCountProperty(Fuse.Layouts.ColumnLayout obj) { _obj = obj;  }
    protected override int OnGet() { return _obj.ColumnCount; }
    protected override void OnSet(int v, object origin) { _obj.ColumnCount = v; }
}

public class RespPanel: Fuse.Controls.StackPanel
{
    internal float2 xsSize;
    internal float2 smSize;
    internal float2 mdSize;
    internal float2 lgSize;
    internal float2 xlSize;
    internal int xs;
    internal int sm;
    internal int md;
    internal int lg;
    internal int xl;
    internal Fuse.Layouts.ColumnLayout colLayout;

    public int Xs{
        get{
            return xs;
        }
        set{
            xs = value;

            var temp1 = new Fuse.Triggers.WhileWindowSize();
            temp1.GreaterThan = xsSize;
            var changeColumnCount = new Fuse.Animations.Change<int>(new RespPanelColumnCountProperty(colLayout));
            temp1.Animators.Add(changeColumnCount);
            changeColumnCount.Value = xs;
            this.Behaviors.Add(temp1);
        }
    }

    public int Sm{
        get{
            return sm;
        }
        set{
            sm = value;

            var temp2 = new Fuse.Triggers.WhileWindowSize();
            temp2.GreaterThan = smSize;
            var changeColumnCount = new Fuse.Animations.Change<int>(new RespPanelColumnCountProperty(colLayout));
            temp2.Animators.Add(changeColumnCount);
            changeColumnCount.Value = sm;
            this.Behaviors.Add(temp2);
        }
    }

    public int Md{
        get{
            return md;
        }
        set{
            md = value;

            var temp3 = new Fuse.Triggers.WhileWindowSize();
            temp3.GreaterThan = mdSize;
            var changeColumnCount = new Fuse.Animations.Change<int>(new RespPanelColumnCountProperty(colLayout));
            temp3.Animators.Add(changeColumnCount);
            changeColumnCount.Value = md;
            this.Behaviors.Add(temp3);
        }
    }

    public int Lg{
        get{
            return lg;
        }
        set{
            lg = value;

            var temp = new Fuse.Triggers.WhileWindowSize();
            temp.GreaterThan = lgSize;
            var changeColumnCount = new Fuse.Animations.Change<int>(new RespPanelColumnCountProperty(colLayout));
            temp.Animators.Add(changeColumnCount);
            changeColumnCount.Value = lg;
            this.Behaviors.Add(temp);
        }
    }

    public int Xl{
        get{
            return xl;
        }
        set{
            xl = value;

            var temp = new Fuse.Triggers.WhileWindowSize();
            temp.GreaterThan = xlSize;
            var changeColumnCount = new Fuse.Animations.Change<int>(new RespPanelColumnCountProperty(colLayout));
            temp.Animators.Add(changeColumnCount);
            changeColumnCount.Value = xl;
            this.Behaviors.Add(temp);
        }
    }

    static RespPanel(){
    }
    public RespPanel(){
        InitializeUX();
    }
    void InitializeUX()
    {
        xsSize=float2(0f,0f);
        smSize=float2(300f,300f);
        mdSize=float2(410f,410f);
        lgSize=float2(1000f,700f);
        xlSize=float2(1280f,1000f);

        colLayout = new Fuse.Layouts.ColumnLayout();
        colLayout.ColumnCount = 1;
        this.Layout = colLayout;
        this.Orientation = Fuse.Layouts.Orientation.Vertical;
    }
}

And then I can use something like:

<RespPanel Xl="5" Lg="4" Md="3" Sm="2" Xs="1" Margin="14,3,14,0">
    <Text Value="Col1"/>
    <Text Value="Col2"/>
    <Text Value="Col3"/>
    <Text Value="Col4"/>
    <Text Value="Col5"/>
</RespPanel>

The problem is that if I run it using the included simulator (local) and I resize the window to test every breakpoint of the 5 different sizes (xs, sm, md, lg and xl) It works just when I go from a small size to a big size, but when I reach the biggest size and I try to resize the window to a smaller size, it doesn’t work for every breakpoint.

Additionally, I really want to suggest to include this kind of responsiveness as a capability to the layout system. I think this would make it even more powerful.

Regards

Hi,

I’m looking into this now. In the meantime, I found a work-around for you that works. You can rewrite

 <Change cols.ColumnCount="{Property test.SmallSize}"/>

To

 <Change Target="cols.ColumnCount" Value="{Property test.SmallSize}"/>

Does the same, and shouldn’t give the error :slight_smile:

Thanks Andersen,

The workaround worked pretty fine, but unfortunately I am facing the same problem I got with the UNO class described on my previous post.

I would like to change the number of columns based on 5 different window sizes, representing from extra small to extra large.

The code that I am using is:

<StackPanel ux:Class="NewClass" ux:Name="test" >
    <int ux:Property="xs"/>
    <int ux:Property="sm"/>
    <int ux:Property="md"/>
    <int ux:Property="lg"/>
    <int ux:Property="xl"/>
    <ColumnLayout ux:Name="cols" ColumnCount="5"/>
    <WhileWindowSize GreaterThan="0,0">
        <Change Target="cols.ColumnCount" Value="{Property test.xs}"/>
    </WhileWindowSize>
    <WhileWindowSize GreaterThan="300,300">
        <Change Target="cols.ColumnCount" Value="{Property test.sm}"/>
    </WhileWindowSize>
    <WhileWindowSize GreaterThan="410,410">
        <Change Target="cols.ColumnCount" Value="{Property test.md}"/>
    </WhileWindowSize>
    <WhileWindowSize GreaterThan="1000,700">
        <Change Target="cols.ColumnCount" Value="{Property test.lg}"/>
    </WhileWindowSize>
    <WhileWindowSize GreaterThan="1280,1000">
        <Change Target="cols.ColumnCount" Value="{Property test.xl}"/>
    </WhileWindowSize>
</StackPanel>

Then I’m using it with something like

<NewClass xs="1" sm="2" md="3" lg="4" xl="5">
    <Text Value="Col-a"/>
    <Text Value="Col-b"/>
    <Text Value="Col-c"/>
    <Text Value="Col-d"/>
    <Text Value="Col-e"/>
</NewClass>

The problem is that it doesn’t work for every single size. I am testing it using the simulator (local) resizing the window. And if I start with a very small window and increase its size progressively, I can validate that every size condition is correctly met, but if then once I reach the biggest size I try to go back to a small size, I realize that not every size condition is met.

This is exactly the same behavior if I implement the class using UNO, that’s why I think it should be a bug.

Regards,

Edzon

Another option is available now in ColumnLayout that you might prefer to use instead. ColumnSize specifies the size of the columns, where the number is then dynamic based on available space.

You can also cause columns expand to fill extra space with Spacing="Fill". The defualt is fixed, which leaves the extra space empty.