Подтвердить что ты не робот

Как я могу разрешить только изменение размера в окне WPF?

Я не хочу, чтобы мое окно изменялось либо "только по горизонтали", либо "только по вертикали". Есть ли свойство, которое я могу установить в моем окне, которое может обеспечить его выполнение, или есть отличный трюк с кодом, который я могу использовать?

4b9b3361

Ответ 1

Вы можете зарезервировать соотношение сторон содержимого с помощью WPF ViewBox с контролем с фиксированной шириной и высотой внутри.

Попробуем попробовать. Вы можете изменить атрибут "Stretch" ​​в ViewBox, чтобы получить разные результаты.

Вот мой screeen shot: enter image description here

<Window x:Class="TestWPF.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">

    <Viewbox Stretch="Uniform">
        <StackPanel Background="Azure" Height="400" Width="300" Name="stackPanel1" VerticalAlignment="Top">
            <Button Name="testBtn" Width="200" Height="50">
                <TextBlock>Test</TextBlock>
            </Button>
        </StackPanel>
    </Viewbox>

</Window>

Ответ 2

Вы всегда можете обработать сообщение WM_WINDOWPOSCHANGING, это позволит вам управлять размером и положением окна во время процесса изменения размера (в отличие от фиксации вещей после того, как пользователь закончил изменение размера).

Вот как вы это делаете в WPF, я объединил этот код из нескольких источников, поэтому в нем могут быть некоторые синтаксические ошибки.

internal enum WM
{
   WINDOWPOSCHANGING = 0x0046,
}

[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWPOS
{
   public IntPtr hwnd;
   public IntPtr hwndInsertAfter;
   public int x;
   public int y;
   public int cx;
   public int cy;
   public int flags;
}

private void Window_SourceInitialized(object sender, EventArgs ea)
{
   HwndSource hwndSource = (HwndSource)HwndSource.FromVisual((Window)sender);
   hwndSource.AddHook(DragHook);
}

private static IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handeled)
{
   switch ((WM)msg)
   {
      case WM.WINDOWPOSCHANGING:
      {
          WINDOWPOS pos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
          if ((pos.flags & (int)SWP.NOMOVE) != 0)
          {
              return IntPtr.Zero;
          }

          Window wnd = (Window)HwndSource.FromHwnd(hwnd).RootVisual;
          if (wnd == null)
          {
             return IntPtr.Zero;
          }

          bool changedPos = false;

          // ***********************
          // Here you check the values inside the pos structure
          // if you want to override tehm just change the pos
          // structure and set changedPos to true
          // ***********************

          if (!changedPos)
          {
             return IntPtr.Zero;
          }

          Marshal.StructureToPtr(pos, lParam, true);
          handeled = true;
       }
       break;
   }

   return IntPtr.Zero;
}

Ответ 3

Это мое решение было.

Вам нужно добавить это в свой тег control/window:

Loaded="Window_Loaded"

И вам нужно поместить это в свой код позади:

private double aspectRatio = 0.0;

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    aspectRatio = this.ActualWidth / this.ActualHeight;
}

protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
    if (sizeInfo.WidthChanged)
    {
        this.Width = sizeInfo.NewSize.Height * aspectRatio;
    }
    else
    {
        this.Height = sizeInfo.NewSize.Width * aspectRatio;
    }
}

Я попробовал трюк Viewbox, и мне это не понравилось. Я хотел заблокировать границу окна до определенного размера. Это было проверено на управление окном, но я полагаю, что он будет работать и на границе.

Ответ 4

Вы можете попробовать воспроизвести эффект, который я часто вижу на веб-сайтах Flash Video. Они позволяют вам развернуть окно браузера любым способом, но только растянуть область презентации так, чтобы она соответствовала наименьшей высоте или ширине.

Например, если вы растягиваете окно по вертикали, ваше приложение не будет изменять размер. Это просто добавит черные полосы в верхнюю и нижнюю части области отображения и останется вертикально центрированным.

Это может быть или не быть возможно с WPF; Я не знаю.

Ответ 5

Я ожидал, что вы можете двусторонне связать ширину с высотой, используя конвертер значений, чтобы поддерживать соотношение сторон. Передача формата изображения в качестве параметра преобразователя сделает его более общим.

Итак, я попробовал это - привязка без конвертера сначала:

<Window 
    ...
    Title="Window1" Name="Win" Height="500" 
    Width="{Binding RelativeSource={RelativeSource self}, 
                    Path=Height, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <StackPanel>
        <TextBlock>Width:</TextBlock>
        <TextBlock Text="{Binding ElementName=Win, Path=Width}" />
        <TextBlock>Height:</TextBlock>
        <TextBlock Text="{Binding ElementName=Win, Path=Height}" />
    </StackPanel>    
</Window>

Странно, привязка ведет себя так, как если бы она была односторонней, и объявленная ширина окна (как показано в TextBlock) не соответствует размеру на экране!

Идею можно было бы преследовать, но это странное поведение нужно было бы сначала разобрать.

Надеюсь, что это поможет!

Ответ 6

Это может быть немного поздно, но вы можете просто поместить его в свой код позади....

Private Sub UserControl1_SizeChanged(ByVal sender As Object, ByVal e As System.Windows.SizeChangedEventArgs) Handles Me.SizeChanged
    If e.HeightChanged Then
        Me.Width = Me.Height
    Else
        Me.Height = Me.Width
    End If
End Sub

Ответ 7

В примере кода:

if (sizeInfo.WidthChanged)     
{         
    this.Width = sizeInfo.NewSize.Height * aspectRatio;    
}     
else     
{         
    this.Height = sizeInfo.NewSize.Width * aspectRatio; 
} 

Я считаю, что второе вычисление должно быть:

this.Height = sizeInfo.NewSize.Width * (1/aspectRatio);  

Я сделал вариацию этой работы в обработчике событий "SizeChanged". Поскольку я хотел, чтобы ширина была контрольным размером, я просто заставлял высоту соответствовать ей с вычислением формы:

if (aspectRatio > 0)
// enforce aspect ratio by restricting height to stay in sync with width.  
this.Height = this.ActualWidth * (1 / aspectRatio);

Вы можете отметить проверку aspectRatio > 0,... Я сделал это, потому что обнаружил, что он пытался вызвать мои обработчики, которые изменили размер до того, как метод Load также присвоил aspectRatio.

Ответ 8

Возможно, слишком поздно, но я нашел решение из блога Майка О'Брайена, и он работает очень хорошо. http://www.mikeobrien.net/blog/maintaining-aspect-ratio-when-resizing/ Ниже приведен код из его блога:

<Window ... SourceInitialized="Window_SourceInitialized" ... >
    ...
Window>

public partial class Main : Window
{
    private void Window_SourceInitialized(object sender, EventArgs ea)
    {
        WindowAspectRatio.Register((Window)sender);
    }
    ...
}


internal class WindowAspectRatio
{
    private double _ratio;

    private WindowAspectRatio(Window window)
    {
        _ratio = window.Width / window.Height;
        ((HwndSource)HwndSource.FromVisual(window)).AddHook(DragHook);
    }

    public static void Register(Window window)
    {
        new WindowAspectRatio(window);
    }

    internal enum WM
    {
        WINDOWPOSCHANGING = 0x0046,
    }

    [Flags()]
    public enum SWP
    {
        NoMove = 0x2,
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct WINDOWPOS
    {
        public IntPtr hwnd;
        public IntPtr hwndInsertAfter;
        public int x;
        public int y;
        public int cx;
        public int cy;
        public int flags;
    }

    private IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handeled)
    {
        if ((WM)msg == WM.WINDOWPOSCHANGING)
        {
            WINDOWPOS position = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));

            if ((position.flags & (int)SWP.NoMove) != 0 || 
                HwndSource.FromHwnd(hwnd).RootVisual == null) return IntPtr.Zero;

            position.cx = (int)(position.cy * _ratio);

            Marshal.StructureToPtr(position, lParam, true);
            handeled = true;
        }

        return IntPtr.Zero;
    }
}