我曾经在WPF中通过重写protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
解决了类似的问题。
当用户放大屏幕时,我需要重新排列一些东西,以便可以保持纵横比调整图像大小,并为3倍和4倍缩放腾出空间,必须移动控件并将其覆盖在图像上。
我通过使用最外层的Canvas元素,在其中嵌套了几个Grid来处理大部分布局和需要移动或叠加在StackPanels中的控件集。
请注意,我尝试通过从初始布局驱动逻辑来避免过多的硬编码 - 如果您在XAML中稍微重新排列一下,它仍应该能够根据与几个关键对象相关的大小调整物品。
/**
* Stores sizes used by OnRenderSizeChanged() to measure relative changes, based off the size of elements initially drawn.
*
* Everything is driven by the size and position of the grid rightSideControls because that is immediately
* adjacent to the visible bitmap firebar when we open.
*
* SEImagesBitmap is drawn in the background so its size can actually be way too big
*
*/
private void InitSizesOnceConstructed()
gotSizes = true;
initialBitmapSize.Height = SEImagesBitmap.ActualHeight;
initialBitmapSize.Width = SEImagesBitmap.ActualWidth;
initialRightSideControlsBounds = new Rect(
Canvas.GetLeft(rightSideControls),
0,
rightSideControls.ActualWidth,
rightSideControls.ActualHeight);
initialWindowExtra.Width = Width - (initialRightSideControlsBounds.Right + 4);
initialWindowExtra.Height = Height - (Canvas.GetTop(bottomControls) + bottomControls.ActualHeight);
}
/**
* Moves things around to fit once the window is big enough for the main image to rescale, starting from trying to fit at scale 1 and moving up.
*
* Relies heavily on SizeAtScale() to decide if that scale will fit, but the actual layout is done here.
*
* May move controls on top of the image, so changes text color to white to make it visible on the image typical black margin.
*
* Standard event invoked after the size is changed for any reason.
* @warning if you change the layout logic in here must change SizeAtScale() to match!
*/
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
Size newSize = sizeInfo.NewSize;
int scale = 1;
Size minSizeForScale = new Size(0, 0);
for (; scale <= MAX_IMAGE_SCALE; scale++)
}
if (drawingCanvas.Scale != scale || justForcedMaximize)
putBottomControlsOnImage = true;
}
drawingCanvas.SetScale(scale);
drawingCanvas.Width = scale * 256;
drawingCanvas.Height = scale * 256;
SEImagesBitmap.Width = scale * initialBitmapSize.Width;
SEImagesBitmap.Height = scale * initialBitmapSize.Height;
Canvas.SetLeft(fireLegendGrid, SEImagesBitmap.Width);
fireLegendGrid.Height = SEImagesBitmap.Height;
Canvas.SetLeft(bottomLeftControls, 0);
double newTopForBottomLeftControls = SEImagesBitmap.Height;
if (putBottomControlsOnImage)
lastResizePutControlsOverImage = true;
TEXT_Mask.Foreground = Brushes.White;
rightSideControls.Height = newTopForBottomLeftControls + bottomLeftControls.Height;
}
else
Canvas.SetTop(bottomLeftControls, newTopForBottomLeftControls);
Canvas.SetLeft(rightSideControls, SEImagesBitmap.Width + fireLegendGrid.Width);
if (scale > 2)
else
NudgeWindowToFit();
}
}
base.OnRenderSizeChanged(sizeInfo);
}
private Size SizeAtScale(int tryScale)
}
return new Size(newWidth, newHeight);
}
protected override void OnActivated(EventArgs e)
...
InitSizesOnceConstructed();
}
整个XAML文件:
<Window
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:dt="clr-namespace:DrawToolsLib;assembly=DrawToolsLib"
xmlns:ads="clr-namespace:ADS_Controls;assembly=ADS_UpDownControl"
xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006'
xmlns:d='http://schemas.microsoft.com/expression/blend/2008'
mc:Ignorable='d'
Height="367" Width="452" Top="2" Left="689"
Title='Spin-Echo Images' x:Class='Blah.SEImages'
Style="{StaticResource windowStyle}" >
<Window.Resources>
<Image x:Key="DrawRectangle" Width="16" Height="16" Source="img\DrawRectangle.bmp"/>
<Image x:Key="DrawRectangleDark" Width="16" Height="16" Source="img\DrawRectangleDark.bmp"/>
<Image x:Key="DrawOval" Width="16" Height="16" Source="img\DrawOval.bmp"/>
<Image x:Key="DrawOvalDark" Width="16" Height="16" Source="img\DrawOvalDark.bmp"/>
<Image x:Key="DrawFree" Width="16" Height="16" Source="img\DrawFree.bmp"/>
<Image x:Key="DrawFreeDark" Width="16" Height="16" Source="img\DrawFreeDark.bmp"/>
<Image x:Key="DrawSubQ" Width="16" Height="16" Source="img\DrawSubQ.bmp"/>
<Image x:Key="DrawSubQDark" Width="16" Height="16" Source="img\DrawSubQDark.bmp"/>
<Image x:Key="DrawCuts" Width="16" Height="16" Source="img\DrawCuts.bmp"/>
<Image x:Key="DrawCutsDark" Width="16" Height="16" Source="img\DrawCutsDark.bmp"/>
<Image x:Key="DrawEdge" Width="16" Height="16" Source="img\DrawEdge.bmp"/>
<Image x:Key="DrawEdgeDark" Width="16" Height="16" Source="img\DrawEdgeDark.bmp"/>
<Style TargetType="{x:Type ToggleButton}" x:Key="RectControlStyle">
<Setter Property="Content" Value="{DynamicResource DrawRectangle}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="{DynamicResource DrawRectangleDark}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type ToggleButton}" x:Key="OvalControlStyle">
<Setter Property="Content" Value="{DynamicResource DrawOval}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="{DynamicResource DrawOvalDark}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type ToggleButton}" x:Key="FreeControlStyle">
<Setter Property="Content" Value="{DynamicResource DrawFree}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="{DynamicResource DrawFreeDark}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type ToggleButton}" x:Key="ShowControlStyle">
<Setter Property="Content" Value="{DynamicResource DrawSubQ}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="{DynamicResource DrawSubQDark}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type ToggleButton}" x:Key="DarkControlStyle">
<Setter Property="Content" Value="{DynamicResource DrawCuts}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="{DynamicResource DrawCutsDark}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type ToggleButton}" x:Key="Free2ControlStyle">
<Setter Property="Content" Value="{DynamicResource DrawEdge}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="{DynamicResource DrawEdgeDark}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Canvas x:Name="outerCanvas" Margin="0,0,4,4" HorizontalAlignment="Left" VerticalAlignment="Top">
<Canvas x:Name="BitmapAndToolsOverlay" Width="305" Height="256" >
<Image x:Name="SEImagesBitmap" Margin="0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<dt:DrawingCanvasMasking x:Name="drawingCanvas" Background="
</Canvas>
<Grid x:Name="fireLegendGrid" Height="256" Width="40" Canvas.Left="305" Canvas.Top="0">
<Grid.RowDefinitions>
<RowDefinition Height="17"/>
<RowDefinition Height="*"/>
<RowDefinition Height="17"/>
<RowDefinition Height="*"/>
<RowDefinition Height="17"/>
<RowDefinition Height="*"/>
<RowDefinition Height="17"/>
</Grid.RowDefinitions>
<TextBlock x:Name='TEXT_WhiteMark' Grid.Column="0" Grid.Row="0" Text="3499"/>
<TextBlock x:Name='TEXT_YellowMark' Grid.Column="0" Grid.Row="2" Width='31' Text="2300" />
<TextBlock x:Name='TEXT_RedMark' Grid.Column="0" Grid.Row="4" Width='31' Text="1100"/>
<TextBlock x:Name='TEXT_BlackMark' Grid.Column="0" Grid.Row="6" Width='31' Text="0" />
</Grid>
<Grid x:Name="rightSideControls" Height="288" Canvas.Left="345" Canvas.Top="0" >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="16"/>
<RowDefinition Height="16"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<Slider x:Name='CNTL_WhiteLevel' Grid.Column="0" Grid.Row="0" Maximum='255' Width="24" Minimum='0' Orientation='Vertical' Margin="0,4,0,4"/>
<Slider x:Name='CNTL_BlackLevel' Grid.Column="1" Grid.Row="0" Maximum='255' Width="24" Minimum='0' Orientation='Vertical' Margin="0,4,0,4"/>
<TextBlock x:Name='TEXT_WhiteSetting' Grid.Column="0" Grid.Row="1" Width='37' Height='16' HorizontalAlignment="Stretch" TextAlignment="Center" Text='1200'/>
<TextBlock x:Name='TEXT_BlackSetting' Grid.Column="1" Grid.Row="1" Width='37' Height='16' HorizontalAlignment="Stretch" TextAlignment="Center" Text='0'/>
<TextBlock x:Name='TEXT_Black' Grid.Column="0" Grid.Row="2" Height='16' HorizontalAlignment="Center" TextAlignment="Center"><Run Text="Black"/></TextBlock>
<TextBlock x:Name='TEXT_White' Grid.Column="1" Grid.Row="2" Height='16' TextAlignment="Center"><Run Text="White"/></TextBlock>
</Grid>
<StackPanel x:Name="bottomLeftControls" Height="27" Canvas.Left="0" Canvas.Top="256" Orientation="Horizontal" Margin="0,4">
<TextBlock x:Name='TEXT_Mask' Width='Auto' Height='Auto' Margin="4,0" VerticalAlignment="Center"><Run Text="Mask:"/></TextBlock>
<ComboBox x:Name='CNTL_ROIType' Width='88' Height="21" SelectedIndex="0" Margin="0,0,4,0">
<ComboBoxItem Content="Analysis"/>
<ComboBoxItem Content="Phantom"/>
<ComboBoxItem Content="Background"/>
<ComboBoxItem Content="Density"/>
</ComboBox>
<ComboBox x:Name='CNTL_Operation' Width='61' Height="21" SelectedIndex="0" Margin="4,0">
<ComboBoxItem Content="Add"/>
<ComboBoxItem Content="Cut"/>
</ComboBox>
<Button x:Name='CNTL_Clear' Width='23' Height='23' Margin="4,0,0,0">
<Image Width="16" Height="16" Source="img\ClearROI.bmp"/>
</Button>
<Canvas x:Name="alternatingVisibilityTools" Margin="0,3">
<StackPanel x:Name="CommonToolsLayer" Canvas.Top="-1" Canvas.Left="0" Orientation="Horizontal" Width="71" Height="23">
<ToggleButton x:Name='CNTL_CommonToolsLayer_Rectangle' Checked="CNTL_CommonToolsLayer_Rectangle_Click" Style="{StaticResource RectControlStyle}" />
<ToggleButton x:Name='CNTL_CommonToolsLayer_Oval' Checked="CNTL_CommonToolsLayer_Oval_Click" Style="{StaticResource OvalControlStyle}" />
<ToggleButton x:Name='CNTL_CommonToolsLayer_Free' Checked="CNTL_CommonToolsLayer_Free_Click" Style="{StaticResource FreeControlStyle}" />
</StackPanel>
<StackPanel x:Name="DensityLayer" Canvas.Top="-1" Canvas.Left="0" Orientation="Horizontal" Visibility="Hidden" Height="23">
<ToggleButton x:Name='CNTL_DensityLayer_Show' Checked="CNTL_DensityLayer_Show_Click" Style="{StaticResource ShowControlStyle}" />
<ToggleButton x:Name='CNTL_DensityLayer_Dark' Checked="CNTL_DensityLayer_Dark_Click" Style="{StaticResource DarkControlStyle}" />
<ToggleButton x:Name='CNTL_DensityLayer_Free' Checked="CNTL_DensityLayer_Free_Click" Style="{StaticResource Free2ControlStyle}" />
</StackPanel>
</Canvas>
</StackPanel>
<StackPanel x:Name='bottomControls' Orientation="Horizontal" Canvas.Left="0" Canvas.Top="291" Margin="4,0,0,0" Height="34" >
<Button x:Name='CNTL_Zoom' Width='27' Height="27" Click="CNTL_Zoom_Click">
<Image Width="21" Height="21" Source="img\DoZoom.bmp"/>
</Button>
<ads:ADS_UpDownControl x:Name="CNTL_ImageSwitch" Maximum='7' Minimum='0' Margin="4,0"/>
<TextBox x:Name='CNTL_ImageNames' MinWidth="180" Height="27" Text="TestCase3A.2_TE06.txt" Margin="4,0"/>
<Button x:Name='CNTL_ShowHeader' Height="24" Content="Show Header" Margin="4,0" Padding="4,0"/>
<Button x:Name='CNTL_SaveROI' Height="24" Content="Save ROI" Margin="4,0" Padding="4,0"/>
</StackPanel>
</Canvas>
</Window>
StackPanel
的位置取决于Grid
的Width
和Height
。即使使用Auto
也不起作用。 - Tsu