Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF网格行高度自动,最大为星形(*)_C#_.net_Wpf_Datagrid - Fatal编程技术网

C# WPF网格行高度自动,最大为星形(*)

C# WPF网格行高度自动,最大为星形(*),c#,.net,wpf,datagrid,C#,.net,Wpf,Datagrid,我有一个UserControl,其中包含以下代码(简化以使其可读): 现在,我希望所有控件都显示在堆栈中,但仅限于窗口的大小 问题是,当我在DataGrid中有大量数据时,数据会超出边界,最后一个文本块不可见,DataGrid滚动条也不会出现 当我为Star(*)设置第三行定义时,数据网格的大小对于大量项目来说是合适的,但是如果数据网格中只有很少的项目,最后一个文本块将显示在屏幕底部(根据需要不直接在数据网格之后) 当替代Grid I user StackPanel时,它看起来与上面代码中的

我有一个UserControl,其中包含以下代码(简化以使其可读):


现在,我希望所有控件都显示在堆栈中,但仅限于窗口的大小

问题是,当我在DataGrid中有大量数据时,数据会超出边界,最后一个文本块不可见,DataGrid滚动条也不会出现

当我为Star(*)设置第三行定义时,数据网格的大小对于大量项目来说是合适的,但是如果数据网格中只有很少的项目,最后一个文本块将显示在屏幕底部(根据需要不直接在数据网格之后)

当替代Grid I user StackPanel时,它看起来与上面代码中的相同。如果我使用DockPanel,DataGrid可以正常滚动,但最后一个TextBlock根本不可见

我可以想象将第三行定义为Height=“Auto”MaxHeight=“*”,但这显然是不可能的


您能帮忙吗?

您需要以编程方式完成此操作,而不是使用xaml。这是因为您希望它做两件不同的事情:

  • 如果只有几个项目,请将最后一个文本块放在靠近数据网格的位置
  • 如果DataGrid有大量项,则保持最后一个文本块可见
  • 执行此操作需要您连接到代码隐藏中的事件,确定最后一个TextBlock是否消失,然后相应地调整RowDefinition上的Height=“Auto”或Height=“*”,然后更新Layout

    这是一个示例项目。为了简单起见,我用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.";
            }
        }
    
    
    
    代码隐藏:

        <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.";
            }
        }
    
    public分部类主窗口:窗口,INotifyPropertyChanged
    {
    私有字符串输出;
    公共主窗口()
    {
    初始化组件();
    此.Loaded+=已加载;
    this.DataContext=this;
    }
    /// 
    ///处理数据网格的SizeChanged事件。
    /// 
    /// 
    /// 
    私有void MyDataGrid_SizeChanged(对象发送方,SizeChangedEventArgs e)
    {
    如果(!IsUserVisible(lastTextBlock,this))
    {
    if(this.myRowDefinition.Height==GridLength.Auto)
    {
    //编辑行定义并重新绘制它
    this.myRowDefinition.Height=新的GridLength(1,GridUnitType.Star);
    }
    }
    其他的
    {
    if(this.myRowDefinition.Height!=GridLength.Auto&&CanDataGridBeSmaller(this.myRowDefinition.ActualHeight))
    {
    //如果datagrid可以更小,请将行定义更改回“自动”
    this.myRowDefinition.Height=GridLength.Auto;
    }
    }
    this.UpdateLayout();
    }
    /// 
    ///DataGrid可能会占用比实际需要更多的空间。如果您正在调整窗口大小,则可能会发生这种情况。
    ///因此,始终检查以确保如果可以使DataGrid变小,那么它将保持较小。
    /// 
    ///DataGrid行定义的实际高度
    /// 
    私人布勒烛台(双倍实际重量)
    {
    //创建一个与datagrid等效的虚拟控件(出于我的目的,为了简单起见,我使用了Textblock,所以我将在这里完全重新创建它)。
    TextBlock dummy=new TextBlock(){TextWrapping=TextWrapping.Wrap,FontSize=64,Text=this.Output};
    dummy.Measure(新尺寸(this.myGrid.ActualWidth,this.myGrid.ActualHeight));
    //获取假人高度,并将其与实际高度进行比较
    if(dummy.DesiredSize.Heightthis.Output;设置{this.Output=value;this.PropertyChanged?.Invoke(this,new-propertychangedventargs(nameof(Output));}
    私有无效按钮\u单击(对象发送者,路由目标e)
    {
    此。输出="知识本身是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德如果你不轻率,就必须为自己的行为负责;
    }
    }
    
    启动时的输出示例: