gpt4 book ai didi

c# - WPF 网格行高自动,最大星号 (*)

转载 作者:行者123 更新时间:2023-12-04 09:36:47 24 4
gpt4 key购买 nike

我有一个带有以下代码的 UserControl(已简化以使其可读):

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<TextBlock Grid.Row="0" />
<TextBlock Grid.Row="1" />
<DataGrid Grid.Row="2" />
<TextBlock Grid.Row="3" />
</Grid>
现在我希望所有控件都显示在一个堆栈中,但仅限于窗口的大小。
问题是,当我在 DataGrid 中有大量数据时,它会超出边界并且最后一个 TextBlock 不可见 - 也不会出现 DataGrid 滚动条。
当我为 Star (*) 设置第三行定义时,DataGrid 的大小适合大量项目,但如果 DataGrid 中的项目很少,最后一个 TextBlock 出现在屏幕底部(不是紧接在后面) DataGrid 根据需要)。
当我使用 StackPanel 而不是 Grid 时,它看起来与上面的代码相同。如果我使用 DockPanel,DataGrid 可以正确滚动,但最后一个 TextBlock 根本不可见。
我想将第三行定义为 的解决方案高度=“自动” MaxHeight="*" ,但这显然是不可能的。
你能帮忙吗?

最佳答案

您需要以编程方式执行此操作,而不是在 xaml 中执行此操作。这是因为您希望它做两件不同的事情:

  • 如果只有几个项目,请将最后一个 TextBlock 靠近 DataGrid。
  • 如果 DataGrid 有大量项目,则保持最后一个 TextBlock 可见。

  • 这样做需要您在代码隐藏中 Hook 事件,确定最后一个 TextBlock 是否消失,然后在 RowDefinition 上相应地调整 Height="Auto"或 Height="*",然后是 UpdateLayout。
    这是一个示例项目。为简单起见,我用 TextBlock 替换了您的 DataGrid。
    XAML:
        <Grid>
    <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition/>
    </Grid.RowDefinitions>
    <Button Content="Make Grid.Row=2 Long, But Keep Text 3 Visible" Click="Button_Click" HorizontalAlignment="Center" Margin="5" Padding="5,10"/>
    <Grid Grid.Row="1" x:Name="myGrid">
    <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
    <RowDefinition x:Name="myRowDefinition" Height="Auto"/>
    <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Text="This is Text 1" Background="Red"/>
    <TextBlock Grid.Row="1" Text="This is Text 2" Background="Green"/>
    <TextBlock Grid.Row="2" x:Name="myDataGrid" FontSize="64" Text="{Binding Output}" TextWrapping="Wrap" Background="Blue"/>
    <TextBlock Grid.Row="3" x:Name="lastTextBlock" Text="This is Text 3" Background="Violet"/>
    </Grid>
    </Grid>
    代码隐藏:
        public partial class MainWindow : Window, INotifyPropertyChanged
    {
    private string output;

    public MainWindow()
    {
    InitializeComponent();
    this.Loaded += OnLoaded;
    this.DataContext = this;
    }

    /// <summary>
    /// Handles the SizeChanged event of your data grid.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void MyDataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
    {
    if (!IsUserVisible(lastTextBlock, this))
    {
    if (this.myRowDefinition.Height == GridLength.Auto)
    {
    // Edit the row definition and redraw it
    this.myRowDefinition.Height = new GridLength(1, GridUnitType.Star);
    }
    }
    else
    {
    if (this.myRowDefinition.Height != GridLength.Auto && CanDataGridBeSmaller(this.myRowDefinition.ActualHeight))
    {
    // If the datagrid can be smaller, change the row definition back to Auto
    this.myRowDefinition.Height = GridLength.Auto;
    }
    }
    this.UpdateLayout();
    }

    /// <summary>
    /// It is possible for the DataGrid to take on more space than it actually needs. This can happen if you are messing with the window resizing.
    /// So always check to make sure that if you can make the DataGrid smaller, that it stays small.
    /// </summary>
    /// <param name="actualHeight">the actual height of the DataGrid's row definition</param>
    /// <returns></returns>
    private bool CanDataGridBeSmaller(double actualHeight)
    {
    // Create a dummy control that is equivalent to your datagrid (for my purposes, I used a Textblock for simplicity, so I will recreate it fully here.
    TextBlock dummy = new TextBlock() { TextWrapping = TextWrapping.Wrap, FontSize = 64, Text = this.Output };
    dummy.Measure(new Size(this.myGrid.ActualWidth, this.myGrid.ActualHeight));

    // Get the dummy height and compare it to the actual height
    if (dummy.DesiredSize.Height < myRowDefinition.ActualHeight)
    return true;
    return false;
    }

    /// <summary>
    /// This method determines if the control is fully visible to the user or not.
    /// </summary>
    private bool IsUserVisible(FrameworkElement element, FrameworkElement container)
    {
    if (!element.IsVisible)
    return false;

    Rect bounds = element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
    Rect rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);
    return rect.Contains(bounds);
    }

    /// <summary>
    /// This is purely for setup.
    /// </summary>
    private void OnLoaded(object sender, RoutedEventArgs e)
    {
    this.myDataGrid.SizeChanged += MyDataGrid_SizeChanged;
    this.Output = "This row is short, so Text 3 below me should be flush with my bottom.";
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public string Output { get => this.output; set { this.output = value; this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Output))); } }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
    this.Output = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
    }
    }
    启动时的示例输出:
    enter image description here
    单击顶部按钮后的示例输出:
    enter image description here

    关于c# - WPF 网格行高自动,最大星号 (*),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62539364/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com