enisn / UraniumUI

Uranium is a Free & Open-Source UI Kit for MAUI.
Apache License 2.0
1.13k stars 132 forks source link

Treeview checkbox cant be wrapped #668

Open Robert0309 opened 4 months ago

Robert0309 commented 4 months ago

I am trying to customise my treeview but when I wrap a frame around the checkbox element the checkboxes stop working. This works:

<material:TreeView ItemsSource="{Binding Nodes}" IsExpandedPropertyName="IsExtended" >
    <material:TreeView.ItemTemplate>
        <DataTemplate>
              <material:CheckBox Text="{Binding Name}" >
                  <material:CheckBox.Behaviors>
                      <material:TreeViewHierarchicalSelectBehavior />
                  </material:CheckBox.Behaviors>
              </material:CheckBox>
        </DataTemplate>
    </material:TreeView.ItemTemplate>
</material:TreeView>

but this doesn't:

<material:TreeView ItemsSource="{Binding Nodes}" IsExpandedPropertyName="IsExtended" >
    <material:TreeView.ItemTemplate>
        <DataTemplate>
            <Frame>
                <material:CheckBox Text="{Binding Name}" >
                    <material:CheckBox.Behaviors>
                        <material:TreeViewHierarchicalSelectBehavior />
                    </material:CheckBox.Behaviors>
                </material:CheckBox>
            </Frame>
        </DataTemplate>
    </material:TreeView.ItemTemplate>
</material:TreeView>

I am using the example from the docs.

enisn commented 4 months ago

It seems it searches in all children hierarchy in the code https://github.com/enisn/UraniumUI/blob/da0b199f1024afd221474759960ed2aa24150491/src/UraniumUI.Material/Controls/TreeViewHierarchicalSelectBehavior.cs#L112C22-L112C45

But there can be some logical issues. I'll take a look at it asap. You can copy this behaviour to your project and customize as you wish until the solution is released

Robert0309 commented 4 months ago

thanx I got it working by motiving the FindCheckBox function. I tried to get a recursive function working but fail. for anyone else who would like to do something like this right now, all you have to do is all you have to do is copy the file @enisn previously provided into your project. I renamed mine to CustomTreeViewHierarchicalSelectBehavior however I don't know id that is necessary. Edit the FindCheckBox as shown:

private static CheckBox FindCheckBox(TreeViewNodeHolderView child) {
        if (child.NodeView is CheckBox checkBox) {
            return checkBox;
        }

        var frame = (Frame)child.NodeView;

        checkBox = (CheckBox)frame.Children[0];

        return checkBox;

        return child.FindInChildrenHierarchy<CheckBox>();

        throw new InvalidOperationException("CheckBox isn't in a TreeView ItemTemplate");
    }

this can also be staked (I wanted to wrap the frame in a swipeview) :

    private static CheckBox FindCheckBox(TreeViewNodeHolderView child) {
        if (child.NodeView is CheckBox checkBox) {
            return checkBox;
        }

        var swipeview = (SwipeView)child.NodeView;

        var frame = (Frame)swipeview.Children[0];

        checkBox = (CheckBox)frame.Children[0];

        return checkBox;

        return child.FindInChildrenHierarchy<CheckBox>();

        throw new InvalidOperationException("CheckBox isn't in a TreeView ItemTemplate");
    }

you can also simplify it to this:

    private static CheckBox FindCheckBox(TreeViewNodeHolderView child) {
        if (child.NodeView is CheckBox checkBox) {
            return checkBox;
        }

        return (CheckBox)((Frame)((SwipeView)child.NodeView).Children[0]).Children[0];

        return child.FindInChildrenHierarchy<CheckBox>();

        throw new InvalidOperationException("CheckBox isn't in a TreeView ItemTemplate");
    }

Hope this helps any one who has this problem until it gets fixed.

Robert0309 commented 4 months ago

@enisn I have started working on a way to drag an drop within the treeview. This meant that I had to wrap the checkbox in lots of stuff making it quite unreadable as you can see hear: return (CheckBox)((Microsoft.Maui.Controls.Grid)((Frame)((Microsoft.Maui.Controls.Grid)((SwipeView)child.NodeView).Children[0]).Children[0]).Children[0]).Children[0]; so I went back to writing a recursive function. I settled on this:

    private static CheckBox FindCheckBoxRecursively(View view) {
        if(view is CheckBox checkBox) {
            return checkBox;
        }
        // For SwipeViews | Frames
        ContentView? contentView = view as ContentView;
        if(contentView != null){
            foreach(View child in contentView.Children) {
                checkBox = FindCheckBoxRecursively(child);
                if (checkBox != null) {
                    return checkBox;
                }
            }        
        }
        // For Grids
        Microsoft.Maui.Controls.Layout? layout = view as Microsoft.Maui.Controls.Layout;
        if(layout != null) {
            foreach(View child in layout.Children) {
                checkBox = FindCheckBoxRecursively(child);
                if (checkBox != null) {
                    return checkBox;
                }
            }
        }

        return null;
    }

I have tested this on a Grid, SwipeView And Frame. not shore if it will work for every thing but I hope this helps.

this function is called within the normal FindCheckBox func with this code: return FindCheckBoxRecursively(child.NodeView);

enisn commented 4 months ago

Hi,

This method should make it already https://github.com/enisn/UraniumUI/blob/da0b199f1024afd221474759960ed2aa24150491/src/UraniumUI/Extensions/ViewExtensions.cs#L30

It checks all the descendants to find a specific type in the hierarchy, maybe there can be a bug in this method, I need to take a look at it