wpf 窗口最大化时如何使所有控件按比例调整大小?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19393774/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:58:49  来源:igfitidea点击:

How to make all controls resize accordingly proportionally when window is maximized?

wpfc#-4.0mvvm

提问by Shawn

When I clicked on the maximize button the window is maximized but the controls are not resized proportionally. What is the best way to make the controls resize accordingly? I am using MVVM.

当我点击最大化按钮时,窗口被最大化,但控件没有按比例调整大小。使控件相应地调整大小的最佳方法是什么?我正在使用 MVVM。

Here is my code.

这是我的代码。

<Window x:Class="DataTransfer.View.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Icon="/DataTransfer;component/View/Images/ms_msnexplore.gif"

        ResizeMode="CanResizeWithGrip"
        Title="Window1" Height="500" Width="600">
    <!--Style="{DynamicResource OfficeStyle}"-->
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!--<ResourceDictionary Source="/DataTransfer;component/View/WindowBase.xaml" />-->
                <!--<ResourceDictionary Source="/DataTransfer;component/Themes/WPFThemes/CalendarResource.xaml" />-->
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width ="*" />
    </Grid.ColumnDefinitions>
        <Button Content="Button" HorizontalAlignment="Left" Margin="52,28,0,0" VerticalAlignment="Top" Width="75" Height="22" />
        <DatePicker Name="dp" HorizontalAlignment="Left" Margin="175,25,0,0" VerticalAlignment="Top" Width="123" Text="aaa" GotFocus="DateGotFocused" LostFocus="OnLeaveArchiveDate"/>
        <Calendar HorizontalAlignment="Left" Margin="47,162,0,0" VerticalAlignment="Top"/>
        <TextBox Name="t1" HorizontalAlignment="Left" Height="23" Margin="337,23,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" LostFocus="LeaveField" />
        <RadioButton Content="RadioButton" HorizontalAlignment="Left" Margin="88,92,0,0" VerticalAlignment="Top"/>
        <CheckBox Content="CheckBox" HorizontalAlignment="Left" Margin="252,96,0,0" VerticalAlignment="Top"/>
        <ComboBox Name="combo" IsEditable="False" Text="aaa" IsReadOnly="True"
                  HorizontalAlignment="Left" Margin="337,89,0,0" VerticalAlignment="Top" Width="120" 
                  Focusable="True" GotFocus="ComboBoxGotFocused" >
            <ComboBoxItem>January</ComboBoxItem>
            <ComboBoxItem>February</ComboBoxItem>
        </ComboBox>
        <TextBlock HorizontalAlignment="Left" Height="40" Margin="260,184,0,0" TextWrapping="Wrap" Text="Text_Block" VerticalAlignment="Top" Width="257"/>

    </Grid>
</Window>

回答by Sheridan

In WPF there are certain 'container' controls that automatically resize their contents and there are some that don't.

在 WPF 中,某些“容器”控件会自动调整其内容的大小,而有些则不会。

Here are some that do notresize their contents (I'm guessing that you are using one or more of these):

以下是一些不会调整其内容大小的内容(我猜您正在使用其中的一种或多种):

StackPanel
WrapPanel
Canvas
TabControl

Here are some that doresize their contents:

以下是一些确实调整其内容大小的内容:

Grid
UniformGrid
DockPanel

Therefore, it is almost always preferable to use a Gridinstead of a StackPanelunless you do notwant automatic resizing to occur. Please note that it is still possible for a Gridto notsize its inner controls... it all depends on your Grid.RowDefinitionand Grid.ColumnDefinitionsettings:

因此,除非您希望自动调整大小,否则几乎总是最好使用 aGrid而不是 a 。请注意,它仍然是可能的,以大小其内部控制......这一切都取决于你和设置:StackPanelGridGrid.RowDefinitionGrid.ColumnDefinition

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="100" /> <!--<<< Exact Height... won't resize -->
        <RowDefinition Height="Auto" /> <!--<<< Will resize to the size of contents -->
        <RowDefinition Height="*" /> <!--<<< Will resize taking all remaining space -->
    </Grid.RowDefinitions>
</Grid>

You can find out more about the Gridcontrol from the GridClasspage on MSDN. You can also find out more about these container controls from the WPF Container Controls Overviewpage on MSDN.

您可以Grid从MSDN 上的GridClass页面找到有关该控件的更多信息。您还可以从MSDN 上的WPF 容器控件概述页面找到有关这些容器控件的更多信息。

Further resizing can be achieved using the FrameworkElement.HorizontalAlignmentand FrameworkElement.VerticalAlignmentproperties. The default value of these properties is Stretchwhich will stretch elements to fit the size of their containing controls. However, when they are set to any other value, the elements will notstretch.

可以使用FrameworkElement.HorizontalAlignmentFrameworkElement.VerticalAlignment属性进一步调整大小。这些属性的默认值是Stretch拉伸元素以适应其包含控件的大小。但是,当它们设置为任何其他值时,元素将不会拉伸。

UPDATE >>>

更新 >>>

In response to the questions in your comment:

针对您评论中的问题:

Use the Grid.RowDefinitionand Grid.ColumnDefinitionsettings to organise a basic structure first... it is common to add Gridcontrols into the cells of outer Gridcontrols if need be. You can also use the Grid.ColumnSpanand Grid.RowSpanproperties to enable controls to span multiple columns and/or rows of a Grid.

首先使用Grid.RowDefinitionGrid.ColumnDefinition设置来组织基本结构......如果需要,通常将Grid控件添加到外部Grid控件的单元格中。您还可以使用Grid.ColumnSpanGrid.RowSpan属性使控件能够跨越Grid.

It is most common to have at least one row/column with a Height/Widthof "*"which will fill all remaining space, but you can have two or more with this setting, in which case the remaining space will be split between the two (or more) rows/columns. 'Auto' is a good setting to use for the rows/columns that are not set to '"*"', but it really depends on how you want the layout to be.

这是最常用的至少有一排/与列Height/Width"*"这将填补所有的剩余空间,但你可以有两个或两个以上使用此设置,在这种情况下,剩余的空间将是两者之间的分裂(或更多)行/列。'Auto' 是一个很好的设置,用于未设置为 '"*"' 的行/列,但这实际上取决于您希望布局的方式。

There is no Autosetting that you can use on the controls in the cells, but this is just as well, because we want the Gridto size the controls for us... therefore, we don't want to set the Heightor Widthof these controls at all.

没有Auto可以在单元格中的控件上使用的设置,但这也一样,因为我们希望Grid为我们调整控件的大小......因此,我们不想将这些控件的Height或设置Width在全部。

The point that I made about the FrameworkElement.HorizontalAlignmentand FrameworkElement.VerticalAlignmentproperties was just to let you know of their existence... as their default value is already Stretch, you don't generally need to set them explicitly.

我对FrameworkElement.HorizontalAlignmentFrameworkElement.VerticalAlignment属性提出的观点只是让您知道它们的存在......因为它们的默认值已经是Stretch,您通常不需要显式设置它们。

The Marginproperty is generally just used to space your controls out evenly... if you drag and drop controls from the Visual Studio Toolbox, VS will set the Marginproperty to place your control exactly where you dropped it but generally, this is notwhat we want as it will mess with the auto sizing of controls. If you do this, then just delete or edit the Marginproperty to suit your needs.

Margin属性通常仅用于均匀地间隔您的控件...如果您从 Visual Studio 工具箱中拖放控件,VS 将设置该Margin属性以将您的控件准确放置在您放置它的位置,但通常,这不是我们想要的因为它会干扰控件的自动调整大小。如果您这样做,则只需删除或编辑该Margin属性即可满足您的需要。

回答by Ron16

Well, it's fairly simple to do.

嗯,这很简单。

On the window resize event handler, calculate how much the window has grown/shrunk, and use that fraction to adjust 1) Height, 2) Width, 3) Canvas.Top, 4) Canvas.Left properties of all the child controls inside the canvas.

在窗口调整大小事件处理程序上,计算窗口增长/缩小了多少,并使用该分数来调整 1) 高度、2) 宽度、3) Canvas.Top、4) Canvas.Left 内部所有子控件的属性帆布。

Here's the code:

这是代码:

private void window1_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            myCanvas.Width = e.NewSize.Width;
            myCanvas.Height = e.NewSize.Height;

            double xChange = 1, yChange = 1;

            if (e.PreviousSize.Width != 0)
            xChange = (e.NewSize.Width/e.PreviousSize.Width);

            if (e.PreviousSize.Height != 0)
            yChange = (e.NewSize.Height / e.PreviousSize.Height);

            foreach (FrameworkElement fe in myCanvas.Children )
            {   
                /*because I didn't want to resize the grid I'm having inside the canvas in this particular instance. (doing that from xaml) */            
                if (fe is Grid == false)
                {
                    fe.Height = fe.ActualHeight * yChange;
                    fe.Width = fe.ActualWidth * xChange;

                    Canvas.SetTop(fe, Canvas.GetTop(fe) * yChange);
                    Canvas.SetLeft(fe, Canvas.GetLeft(fe) * xChange);

                }
            }
        }

回答by ms600rr

Just thought i'd share this with anyone who needs more clarity on how to achieve this:

只是想我会与任何需要更清楚如何实现这一目标的人分享:

myCanvasis a Canvas control and Parent to all other controllers. This code works to neatly resize to any resolution from 1366 x 768 upward. Tested up to 4k resolution 4096 x 2160

myCanvas是一个 Canvas 控件和所有其他控制器的父级。此代码可以巧妙地将大小调整为 1366 x 768 以上的任何分辨率。测试分辨率高达 4k 4096 x 2160

Take note of all the MainWindow property settings (WindowStartupLocation, SizeToContent and WindowState) - important for this to work correctly- WindowState for my user case requirement was Maximized

记下所有 MainWindow 属性设置(WindowStartupLocation、SizeToContent 和 WindowState) - 这对于它的正常工作很重要- 我的用户案例要求的 WindowState 已最大化

xaml

xml

<Window x:Name="mainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyApp" 
    xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
    x:Class="MyApp.MainWindow" 
     Title="MainWindow"  SizeChanged="MainWindow_SizeChanged"
    Width="1366" Height="768" WindowState="Maximized" WindowStartupLocation="CenterOwner" SizeToContent="WidthAndHeight">

    <Canvas x:Name="myCanvas" HorizontalAlignment="Left" Height="768" VerticalAlignment="Top" Width="1356">
        <Image x:Name="maxresdefault_1_1__jpg" Source="maxresdefault-1[1].jpg" Stretch="Fill" Opacity="0.6" Height="767" Canvas.Left="-6" Width="1366"/>

        <Separator Margin="0" Background="#FF302D2D" Foreground="#FF111010" Height="0" Canvas.Left="-811" Canvas.Top="148" Width="766"/>
        <Separator Margin="0" Background="#FF302D2D" Foreground="#FF111010" HorizontalAlignment="Right" Width="210" Height="0" Canvas.Left="1653" Canvas.Top="102"/>
        <Image x:Name="imgscroll" Source="BcaKKb47i[1].png" Stretch="Fill" RenderTransformOrigin="0.5,0.5" Height="523" Canvas.Left="-3" Canvas.Top="122" Width="580">
            <Image.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform/>
                    <RotateTransform Angle="89.093"/>
                    <TranslateTransform/>
                </TransformGroup>
            </Image.RenderTransform>
        </Image>

.cs

。CS

 private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        myCanvas.Width = e.NewSize.Width;
        myCanvas.Height = e.NewSize.Height;

        double xChange = 1, yChange = 1;

        if (e.PreviousSize.Width != 0)
            xChange = (e.NewSize.Width / e.PreviousSize.Width);

        if (e.PreviousSize.Height != 0)
            yChange = (e.NewSize.Height / e.PreviousSize.Height);

        ScaleTransform scale = new ScaleTransform(myCanvas.LayoutTransform.Value.M11 * xChange, myCanvas.LayoutTransform.Value.M22 * yChange);
        myCanvas.LayoutTransform = scale;
        myCanvas.UpdateLayout();
    }