Dynamic ui with rows and columns

2019-08-31 05:20发布

I want to build an ui with a dynamic grid. At least I think a grid is the way to go. The controls of each cell should be the same, f.e. a TextBox.

Each row can have a different number of cells and I thought about using the ColumnSpan property to make the ui look like

First row, 2 cells
Second row, 3 cells
Third row, 1 cell

Each cell should be part of an f.e. ObservableCollection<MyCellClass> and should have properties like Row, Column, Columnspan, Text.

I know how to build a dynamic grid but I don't know how to set the content of the cells via a template and how to databind the textbox.

Maybe my approach isn't the best and you got some other idea to solve my problem.

标签: wpf mvvm
2条回答
Summer. ? 凉城
2楼-- · 2019-08-31 05:41

You may use a Grid as the ItemsPanel of an ItemsControl, and bind the ItemsSource property to your ObservableCollection.

Assuming that your cell class looks like this:

public class Cell
{
    public int Column { get; set; }
    public int ColumnSpan { get; set; }
    public int Row { get; set; }
    public int RowSpan { get; set; }
    public string Text { get; set; }
}

the XAML may be written like shown below:

<ItemsControl ItemsSource="{Binding}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
            </Grid>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Grid.Column" Value="{Binding Column}"/>
            <Setter Property="Grid.ColumnSpan" Value="{Binding ColumnSpan}"/>
            <Setter Property="Grid.Row" Value="{Binding Row}"/>
            <Setter Property="Grid.RowSpan" Value="{Binding RowSpan}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding Text}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

The following piece of code would initialize two cells of the ItemsControl:

public MainWindow()
{
    InitializeComponent();

    var cells = new ObservableCollection<Cell>();
    cells.Add(new Cell { Column = 0, Row = 0, ColumnSpan = 1, RowSpan = 1, Text = "Cell 1" });
    cells.Add(new Cell { Column = 2, Row = 2, ColumnSpan = 2, RowSpan = 1, Text = "Cell 2" });
    DataContext = cells;
}
查看更多
淡お忘
3楼-- · 2019-08-31 05:52

Why not using something like this?

public class ItemVm 
{
    // here you can put your desired properties, 
    // although you won't need something like ColumnsSpan etc.
}

As underlying structure (viewmodel) for your grid you could use the following property:

public ObservableCollection<ObservableCollection<ItemVm>> Rows { get; } // just an illustration

Now you only need a ListView (or something similar), whose ItemTemplate is again a ListView (or something similar). The ItemTemplate of the inner ListView will be the visual representation of ItemVm.

Please note, that I'm describing an approach according to the MVVM pattern. So you will need a base class for the viewmodels. But you can find plenty of frameworks on the WWW.

查看更多
登录 后发表回答