简体   繁体   中英

Set Dynamic Size of WPF-Object in Code Behind

I am currently trying to design a bar chart looking like this: The amount of rows and bars per row can vary based on the dataTable my chart relies on. (Gaps are not intended, but not my problem atm)

条形图

I am trying to realize my BarChart by using a Grid. My DataTable provides me with a Key, a Length, a Name and a Parent (which is the key of the bar on the right, as each row just splits to right bar into smaller bars).

The grid size is currently based on my maingrid, which is set in the XAML-ViewModel to 900*400. My Bars are currently set to their Length/MaxLength * GridLength (while the first Bar always is MaxLength) and have a Margin, because i wish to have them go from right to left. My Problem is, that I want to make this grid dynamic in size, but if I don't set a fixed size for my MainGrid, the size of my Grid is either NaN or 0.

I removed some pretty confusing parts, but basically this is my code behind:

public MainWindow()
{
    InitializeComponent();
    myTable = new DataTable();
}

InitChart(DataTable dt) //Is called from another class when the DataTable changes
{
    Maingrid.Children.Clear(); //Dispose old BarChart
    myTable = dt;
    Grid grid1 = new Grid();
    grid1.Width = MainGrid.Width;
    grid1.Height = MainGrid.Height;
    // Create Rows 
    int Pa = -1;
        foreach (DataRow rw in myTable.Rows)
        {    

            if (Pa != (int)rw["Parent"])
            {
                RowDefinition rdef = new RowDefinition();
                rdef.Height = new GridLength(20);
                grid.RowDefinitions.Add(rdef);
            }
            Pa = (int)rw["Parent"];
        }

    foreach (DataRow row in myTable.Rows)
    {
     int P = (int)row["Parent"];
       foreach (DataRow rw in myTable.Rows)
        {    
            if ((int)rw["Parent"] == P) //Each row splits the right bar of the previous row, all bars in one row have the previous split bar as their Parent. I draw all Bars with the same Parent in one Row. 
            {
                if ((int)rw["Val"] != 0) //Some Bars are disabled or 0. I don't draw them
                {
                    Rectangle rect = new Rectangle();
                    double L = rw["Val"]; //The Value of one Bar
                    rect.Width = L / nMaxValue * grid.Width; //Calculate width of my Rectange based on the maximal value one bar can have
                    rect.Height = 20; //Just a height
                    rect.Margin = new Thickness( grid.Width - nRowValue/nMaxValue * grid.Width, 0, 0, 0); //Margin to display the bars next to each other
                    rect.Fill = Col;
                    rect.HorizontalAlignment = HorizontalAlignment.Left; //Although i want to have my BarChart go from right to left, I align all bars from on the left and then move them with my margin
                    Grid.SetRow(rect, y);
                    nRowValue = nRowValue - (int)rw["Val"];
                    grid1.Children.Add(rect);
                }
            }
        }
    }

    MainGrid.Children.Add(grid1);
}

XAML:

<UserControl x:Class="WpfApp.MainWindow"
    <Grid x:Name="MainGrid"  Background="#f0f0f0" Height="400" Width="900" />
</UserControl>

I also already tried using a ItemsControl, but I can't seem to get it working.

To make the sizing dynamic, you can use Grid and Grid Columns. Grid is a great layout control as it can use all the available space. Just make sure not to set its or its columns width at any point. This way the outer control (like Page or Window) can control how much space it uses.

The process:

  1. Determine the maxLength value by finding the largest Length in your datatable.
  2. Add that many grid columns into the grid. Make sure not to set column Width. The following code is same as adding *-column, which is what we need:

     for (int i = 0; i < maxLength; i++) { MyGrid.ColumnDefinitions.Add(new ColumnDefinition()); } 
  3. For each bar, create the rectangles but don't set their Width or Margin. Instead set Column and ColumnSpan. For example:

     var rectangle = new Rectangle { Fill = new SolidColorBrush(Colors.LightGray), Opacity = 0.5, Margin = new Thickness(0, -10, 0, 0), Height = 66 }; MyGrid.SetColumn(rectangle, (int)maxLength - data.Length); MyGrid.SetColumnSpan(rectangle, data.Length); 

Hope this helps. Let me know if you encounter any problems.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM