自定义调整大小Window 抖动

Custom resize Window shaking

我想要自定义更大的句柄来调整我的 WPF window。

在关注了几个线程之后(尤其是 this and this) I end up stuck with my window shaking hard because it appear set both Width/Height AND Left/Top make the rendering shaky, as you can see in this gif。

(您可以注意到使用标准 Window 调整大小手柄效果很好,但它们非常薄。也许它是 OS 管理的??)

尝试在代码隐藏中使用自定义 RenderTransform TranslateTransform 但没有成功。

我试图在渲染之前“批量”分配给这两个值(thread.Sleep()using(Dispatcher.DisableProcessing())),但没有任何成功,我认为渲染仍然按顺序进行。

这是我的代码供参考:

XAML

<Window [....]>
[...]
<Style x:Key="ThumbStyle" TargetType="Thumb">
                <Setter Property="Focusable" Value="False" />
                <Setter Property="Background" Value="Red"/>
                <Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType=Window}}" />
                <EventSetter Event="DragStarted" Handler="Thumb_DragStarted"/>
                <EventSetter Event="DragCompleted" Handler="Thumb_DragCompleted"/>
                <EventSetter Event="DragDelta" Handler="Thumb_DragDelta"/>
            </Style>

<!--This doesn't work like it worked for a Canvas unfortunately-->
<Window.RenderTransform>
        <TransformGroup>
            <ScaleTransform x:Name="scl"/>
            <TranslateTransform x:Name="translate"/>
        </TransformGroup>
    </Window.RenderTransform>

<Grid x:Name="RootGrid" Background="Black">    
        <Thumb x:Name="leftSizeGrip"
    Width="20"
    HorizontalAlignment="Left"
    Cursor="SizeWE"
    Style="{StaticResource ThumbStyle}" />
        <Thumb x:Name="rightSizeGrip"
    Width="20"
    HorizontalAlignment="Right"
    Cursor="SizeWE"
    Style="{StaticResource ThumbStyle}" />
        <Thumb x:Name="topSizeGrip"
    Height="20"
    VerticalAlignment="Top"
    Cursor="SizeNS"
    Style="{StaticResource ThumbStyle}" />
        <Thumb x:Name="bottomSizeGrip"
    Height="20"
    VerticalAlignment="Bottom"
    Cursor="SizeNS"
    Style="{StaticResource ThumbStyle}" />
        <!--  Corners  -->
        <Thumb Name="topLeftSizeGrip"
    Width="20"
    Height="20"
    HorizontalAlignment="Left"
    VerticalAlignment="Top"
    Cursor="SizeNWSE"
    Style="{StaticResource ThumbStyle}" />
        <Thumb Name="bottomRightSizeGrip"
    Width="20"
    Height="20"
    HorizontalAlignment="Right"
    VerticalAlignment="Bottom"
    Cursor="SizeNWSE"
    Style="{StaticResource ThumbStyle}" />
        <Thumb Name="topRightSizeGrip"
    Width="20"
    Height="20"               
    HorizontalAlignment="Right"
    VerticalAlignment="Top"
    Cursor="SizeNESW"
    Style="{StaticResource ThumbStyle}" />
        <Thumb Name="bottomLeftSizeGrip"
    Width="20"
    Height="20"
    HorizontalAlignment="Left"
    VerticalAlignment="Bottom"
    Cursor="SizeNESW"
    Style="{StaticResource ThumbStyle}" />
[...]
</Window>

C#

private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
    Thumb senderThumb = sender as Thumb;

    if (senderThumb == null)
        return;

    int horizontalMultiplier = 0, verticalMultiplier = 0;
    
    Window mainWindow = senderThumb.Tag as Window;

    var dragDelta = Mouse.GetPosition(mainWindow) - lastMousePos;
    lastMousePos = Mouse.GetPosition(mainWindow);
    
    if (senderThumb.Name.Contains("right", StringComparison.OrdinalIgnoreCase))
    {                
        horizontalMultiplier = 1;
    }
    if (senderThumb.Name.Contains("left", StringComparison.OrdinalIgnoreCase))
    {
        horizontalMultiplier = -1;
    }            
    if (senderThumb.Name.Contains("bottom", StringComparison.OrdinalIgnoreCase))
    {             
        verticalMultiplier = 1;
    }
    if (senderThumb.Name.ToLower().Contains("top", StringComparison.OrdinalIgnoreCase))
    {
        verticalMultiplier = -1;                
    }            

    var xadjust = mainWindow.Width + horizontalMultiplier * dragDelta.X;
    var yadjust = mainWindow.Height + verticalMultiplier * dragDelta.Y;

    if (xadjust > 0)
    {
        mainWindow.Width = xadjust;
        
        //translate.X += dragDelta.X * (horizontalMultiplier < 0 ? 1 : 0);
        Left += dragDelta.X * (horizontalMultiplier < 0 ? 1 : 0);
        
        if (yadjust > 0)
        {
            mainWindow.Height = yadjust;
            
            //translate.Y += dragDelta.Y * (verticalMultiplier < 0 ? 1 : 0);
            Top += dragDelta.Y * (verticalMultiplier < 0 ? 1 : 0);

            //Canvas.SetTop(myThumbBR, Canvas.GetTop(myThumbBR) +
            //           verticalMultiplier * dragDelta.Y);

            //Canvas.SetTop(myThumbBL, Canvas.GetTop(myThumbBL) +
            //            verticalMultiplier * dragDelta.Y);

            //Canvas.SetTop(myThumbB, Canvas.GetTop(myThumbB) +
            //            verticalMultiplier * dragDelta.Y);
        }

        //Canvas.SetLeft(myThumbBR, Canvas.GetLeft(myThumbBR) +
        //                 horizontalMultiplier * dragDelta.X);

        //Canvas.SetLeft(myThumbTR, Canvas.GetLeft(myThumbTR) +
        //                 horizontalMultiplier * dragDelta.X);

        //Canvas.SetLeft(myThumbR, Canvas.GetLeft(myThumbR) +
        //                 horizontalMultiplier * dragDelta.X);                    
    }
}

private void Thumb_DragCompleted(object sender, DragCompletedEventArgs e)
{
    ((Thumb)sender).Background = Brushes.Red;
}        

private void Thumb_DragStarted(object sender, DragStartedEventArgs e)
{
    ((Thumb)sender).Background = Brushes.IndianRed;
    lastMousePos = Mouse.GetPosition(this);
}

搁置这个问题后,我终于回到了正题。 发现这个 非常有指导意义。 并且,正如另一个 SO , the solution I found was to use ControlzEx WindowChromeBehavior.

所指出的

因为我有点想知道如何使用它,这是我的 XAML :

<Window>
  xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
  xmlns:ctzex="urn:controlzex"
  [...]
</Window>
<i:Interaction.Behaviors>
    <ctzex:WindowChromeBehavior TryToBeFlickerFree="True" ResizeBorderThickness="30" 
                                EnableMinimize="True" EnableMaxRestore="True" KeepBorderOnMaximize="True"/>
</i:Interaction.Behaviors> <!--It does work !!! -->