如何在WPF中避免窗口小于UserControl的最小大小?

24

我有一个用户控件(状态栏),它有一个隐式最小大小(不是通过属性设置的,我的意思是当它达到最小大小时,它不能被减小并被裁剪)。

有没有办法让主窗口知道用户控件即将被裁剪并防止其缩小?使用WPF这样智能的布局系统,它一定知道正在裁剪什么。请看下面的图像:

输入图像描述


你正在使用哪种布局容器(流动布局等)? - Rick Hodder
我目前正在使用一个StackPanel,但是为了实现我的目标,我可以使用任何必要的控件。 - Ignacio Soler Garcia
你最终解决了你的问题吗? - CodeWarrior
一点也不。说实话,我觉得这非常令人沮丧,因为这对我来说看起来很明显。如果你成功了,请回来告诉我。 - Ignacio Soler Garcia
@IgnacioSolerGarcia 这个问题解决了吗? - denver
@denver:不好意思,我不行 :S - Ignacio Soler Garcia
6个回答

20

<Window> 部分内包含 MinHeight="MinSize" MinWidth="MinSize"

其中 MinSize 为期望的整数值,例如 400/350 等。

<Window x:Class="IOTA_WPF.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" 
    WindowState="Maximized"
    MinHeight="400" MinWidth="650">

7
MinSize不是一个固定的值,它取决于DPI设置、字体大小设置等等因素,所以据我所知这不是一个有效的解决方案。不管怎样,谢谢你的尝试。 - Ignacio Soler Garcia
MinSize 意味着我在示例中所解释的期望大小。 - Arijit Mukherjee
1
我明白了,但在WPF中,屏幕上所看到的内容取决于各种设置,即使是固定大小,例如DPI、字体大小等。请查看此链接http://msdn.microsoft.com/en-us/library/ms748828(v=vs.110).aspx。 - Ignacio Soler Garcia
6
兄弟,这正是我在问题中问的内容。 ;) - Ignacio Soler Garcia

15
这是我的解决方法。解决方案特定于我的问题,但可以更改以获得各种所需的调整大小行为。 首先将窗口设置为最初自适应其内容的大小。
<Window ...
    SizeToContent="WidthAndHeight" >

接下来,我设置每个嵌入式控件以报告所需的宽度和高度。大多数内置控件会自动完成此操作。对于自定义控件,您可以通过重写MeasureOverride方法或仅为控件设置宽度和高度来完成此操作。将其设置为您希望控件获得的最小大小。

<MyControl Name="_MyControlName" Width="640" Height="480" />

不要担心这些“硬编码”的值会影响控件的行为。我们接下来会处理这个问题。现在,当窗口显示时,它将自动调整自己以适应您的控件。

接下来,订阅窗口加载事件。

<Window ...
    SizeToContent="WidthAndHeight" Loaded="Window_Loaded" >

在窗口加载事件中,您可以调整窗口及其中控件的大小行为。您可以使控件可以自由调整大小。您还可以将最小窗口大小设置为刚刚布局完成的大小。这样做的好处是,您只需允许布局系统为您找到一个良好的布局即可。您希望利用它的工作。
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        // We know longer need to size to the contents.
        ClearValue(SizeToContentProperty);
        // We want our control to shrink/expand with the window.
        _MyControlName.ClearValue(WidthProperty);
        _MyControlName.ClearValue(HeightProperty);
        // Don't want our window to be able to get any smaller than this.
        SetValue(MinWidthProperty, this.Width);
        SetValue(MinHeightProperty, this.Height);
    }

你放置在Window_Loaded方法中的内容将取决于你想实现的行为。

希望这能帮助其他人节省时间。


嗯...我的担忧在于你的初始布局是基于固定尺寸的,这可能是错误的,并导致错误的初始布局。那么你会如何处理呢? - Ignacio Soler Garcia
那可能是个问题。但对我来说并不是。内置控件(标签、按钮等)通常能够准确报告大小,我们的自定义控件也可以(通过重写MeasureOverride和ArrangeOverride)。对于那些做得不好的控件,您可以在XAML中设置一个合适的宽度/高度,甚至可以根据控件将要显示的数据提前计算出大小,然后通过代码或数据绑定进行设置。在我使用的示例中,我有一个视频控件在这方面表现不佳,因此在显示之前将其大小设置为与视频流匹配(640x480)。 - denver
你好,我实际上是在谈论不同的 DPI 设置、不同的文本大小设置等问题,这些都可能会使固定尺寸变得棘手。你尝试过使用不同 DPI 的应用程序吗? - Ignacio Soler Garcia
注意:我编写了一个自定义的ContentPresenter,它重写了自己的MeasureOverride方法,虽然它仍然测量其所有的子元素,但它总是返回0,0(我称之为CrushablePresenter,因为它“压扁”了该控件的布局测量)。 然后,我将控件放在其中,这些控件不会影响先前评论中表单的最小大小(例如长文本行等)。对于文本修剪等内容,还有一些细节需要处理,但我让读者自行深入挖掘。 - Mark A. Donohoe
这非常有帮助,但我必须进行微调。我将在由模态对话框打开的模态对话框中使用它。 在Loaded中执行似乎会防止WindowStartupLocation="CenterOwner"起作用。如果我改为在ContentRendered中执行,则可以获得正确的窗口位置,并且最小大小仍然有效。 - fadden
显示剩余2条评论

1

您可以将控件的MinHeight属性设置为防止其变得比所需更小。


我尝试过了,但它不起作用 :( 无论如何,我认为布局系统必须知道它正在裁剪用户控件,然后必须有一种方法,而不需要在代码中设置固定值,这会使维护更加困难。 - Ignacio Soler Garcia

1
我知道我有点晚了,但我要说我已经找到了几乎最干净的解决方案。
1.) 创建自定义UserControl(如果您正在使用任何)
public class ExtendedUserControl : UserControl
{
    public static readonly RoutedEvent ContentChangedEvent
    = EventManager.RegisterRoutedEvent(
        "ContentChanged",
        RoutingStrategy.Bubble,
        typeof(RoutedEventHandler),
        typeof(ExtendedUserControl));

    public event RoutedEventHandler ContentChanged
    {
        add { AddHandler(ContentChangedEvent, value); }
        remove { RemoveHandler(ContentChangedEvent, value); }
    }

    protected override void OnContentChanged(object oldContent, object newContent)
    {
        base.OnContentChanged(oldContent, newContent);
        RaiseEvent(new RoutedEventArgs(ContentChangedEvent, this));
    }
}

2.) 将事件附加到您的UserControl

<extended:ExtendedUserControl Height="auto" Width="auto" cal:View.Model="{Binding CurrentModel}" ContentChanged="ExtendedUserControl_ContentChanged"/>

3.) 更新 现在我们来到解决方案的最后一部分。

private void ExtendedUserControl_ContentChanged(object sender, System.Windows.RoutedEventArgs e)
    {
        Thread task = new Thread(() =>
        {
            Dispatcher.Invoke(() =>
            {
                SizeToContent = SizeToContent.WidthAndHeight;
                MinHeight = Height;
                MinWidth = Width;
            });
        });
        task.Start();
    }

干杯


我不再使用WPF了,但我记得有一种叫做Rendered事件的东西。你可以去看看。 - Ignacio Soler Garcia
刚刚检查了一下,我找不到任何关于UserControl或控件本身的事件。此外,我正在使用MVVM,据我所知,视图在绑定创建之前加载。另外,似乎我只是遇到了一些XAML错误,因为现在我能够成功删除线程睡眠而没有出现任何问题。 - MasterOfDesaster

0

你能否将项目放入包含组成部分的行网格中?

所有必须具有最小高度的项目都可以放在具有类似最小高度的行中。

将最小高度相加= Window.MinHeight。因此,窗口永远不能比必要行的集体最小高度更小,因此这些行应始终显示。


0

我记得在某个地方(可能是我错了)读到过,堆栈面板基于无限大具有边框,不能处理这种大小问题。

来自http://msdn.microsoft.com/en-us/library/ms754152.aspx

DockPanel vs StackPanel

尽管DockPanel也可以“堆叠”子元素,但在某些使用场景中,DockPanel和StackPanel并不产生类似的结果。例如,在DockPanel中,子元素的顺序会影响它们的大小,但在StackPanel中则不会。这是因为StackPanel在堆叠方向上测量PositiveInfinity,而DockPanel仅测量可用大小。

帖子中还有一个关于嵌套面板的部分,这可能是您需要的。

或者在底部行中使用网格状态?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接