C# WPF网格行高度自动,最大为星形(*)
我有一个UserControl,其中包含以下代码(简化以使其可读):C# WPF网格行高度自动,最大为星形(*),c#,.net,wpf,datagrid,C#,.net,Wpf,Datagrid,我有一个UserControl,其中包含以下代码(简化以使其可读): 现在,我希望所有控件都显示在堆栈中,但仅限于窗口的大小 问题是,当我在DataGrid中有大量数据时,数据会超出边界,最后一个文本块不可见,DataGrid滚动条也不会出现 当我为Star(*)设置第三行定义时,数据网格的大小对于大量项目来说是合适的,但是如果数据网格中只有很少的项目,最后一个文本块将显示在屏幕底部(根据需要不直接在数据网格之后) 当替代Grid I user StackPanel时,它看起来与上面代码中的
现在,我希望所有控件都显示在堆栈中,但仅限于窗口的大小
问题是,当我在DataGrid中有大量数据时,数据会超出边界,最后一个文本块不可见,DataGrid滚动条也不会出现
当我为Star(*)设置第三行定义时,数据网格的大小对于大量项目来说是合适的,但是如果数据网格中只有很少的项目,最后一个文本块将显示在屏幕底部(根据需要不直接在数据网格之后)
当替代Grid I user StackPanel时,它看起来与上面代码中的相同。如果我使用DockPanel,DataGrid可以正常滚动,但最后一个TextBlock根本不可见
我可以想象将第三行定义为Height=“Auto”和MaxHeight=“*”,但这显然是不可能的
您能帮忙吗?您需要以编程方式完成此操作,而不是使用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)
{
此。输出="知识本身是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德,是一种美德如果你不轻率,就必须为自己的行为负责;
}
}
启动时的输出示例: