2011-05-22 70 views
3

我需要在Grid单元格中显示Image。在图像的顶部,必须在图像的右下角添加一个控件(例如缩放,亮度等)的StackPanel。如何才能做到这一点。我正在执行以下操作,但不知道如何将控件的StackPanel放置在图像的右下角。即使用户调整浏览器窗口大小,也需要保留该位置。XAML:将控件放在图像上

<Grid Grid.Column="1" Height="387" HorizontalAlignment="Left" Name="Image_Border" VerticalAlignment="Top" Width="799"> 
     <Border BorderBrush="Black" BorderThickness="1" Grid.ColumnSpan="2" Height="Auto" HorizontalAlignment="Left" Name="Border_Image" VerticalAlignment="Top" Width="Auto" > 
      <Canvas Height="Auto" HorizontalAlignment="Left" Name="ImageCanvas" VerticalAlignment="Top" Background="Transparent" Width="Auto">        
       <Image Canvas.Left="0" Canvas.Top="0" Height="Auto" Name="imageName" Stretch="None" Width="Auto" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
      </Canvas> 
     </Border>  
     <StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Right"> 
     <!--Stackpanel of controls to be placed at the lower right corner image --> 
     </StackPanel>     
</Grid> 
+0

这不起作用? – tofutim 2011-05-22 09:35:59

+0

不,“StackPanel”的位置取决于“Grid”的“Width”和“Height”。即使'自动'不起作用。 – Tsu 2011-05-22 09:40:02

+0

为什么你有一个边框,然后是一个画布,然后是图像。似乎认真对待复杂。请更详细地描述您的预期布局。如果您已经放大了控件,当图像超出包含网格的大小时,您希望发生什么?放大后是否让控件保留在__image__的右下角有意义? – AnthonyWJones 2011-05-22 12:16:46

回答

0

我解决了WPF了类似的问题通过重写 protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)

我需要随着用户放大屏幕周围洗牌的东西,所以我可以调整图像大小向上保持纵横比和以腾出空间给3倍和4倍变焦必须移动控件,然后在图像上叠加一些控件。

我通过在其中嵌套最外层的Canvas元素来实现这一点,这些元素嵌套在一对网格中以处理大部分布局以及需要在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() 
    { 
     if (gotSizes) 
     { 
      return; 
     } 

     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) 
    { 
     if (gotSizes) 
     { 
      if (lastResizePutControlsOverImage) 
      { // cleanup color changes because we might not put it back 
       lastResizePutControlsOverImage = false; 
       TEXT_Mask.Foreground = Brushes.Black; 
      } 

      Size newSize = sizeInfo.NewSize; 

      // find the largest scale that will fit, regardless of whether we just resized up or down 
      int scale = 1; 
      Size minSizeForScale = new Size(0, 0); // fake init because doesn't like not having one, but always at least once through loop below 
      for (; scale <= MAX_IMAGE_SCALE; scale++) 
      { 
       minSizeForScale = SizeAtScale(scale); 
       if (newSize.Height < minSizeForScale.Height || 
        newSize.Width < minSizeForScale.Width) 
       { 
        scale = Math.Max(1, scale - 1); 
        break; 
       } 
      } 

      if (drawingCanvas.Scale != scale || justForcedMaximize) 
      { 
       justForcedMaximize = false; 
       bool putBottomControlsOnImage = false; 
       if (newSize.Height > 1024) 
       { 
        // do our best to fit on to a 1050 screen 
        if (WindowState == WindowState.Maximized && scale == 3) 
        { 
         scale = 4; 
        } 

        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) 
       { 
        newTopForBottomLeftControls -= 40; // reasonably elegant appearance on bottom of image 
        if (newSize.Height < 1040) 
        { 
         // taskbar on a 1050 screen, take a bit more off 
         newTopForBottomLeftControls -= 24; 
        } 

        lastResizePutControlsOverImage = true; 
        TEXT_Mask.Foreground = Brushes.White; 
        rightSideControls.Height = newTopForBottomLeftControls + bottomLeftControls.Height; // shorten controls to be visible 
       } 
       else 
       { 
        rightSideControls.Height = SEImagesBitmap.Height + (initialRightSideControlsBounds.Height - initialBitmapSize.Height); 
       } 

       Canvas.SetTop(bottomLeftControls, newTopForBottomLeftControls); 
       Canvas.SetLeft(rightSideControls, SEImagesBitmap.Width + fireLegendGrid.Width); 

       // put bottomControls at bottom or for scales > 2 at right of bottomLeftControls 
       if (scale > 2) 
       { 
        // for some weird reason, alternatingVisibilityTools has an ActualWidth of zero 
        double widthTools = Math.Max(CommonToolsLayer.ActualWidth, DensityLayer.ActualWidth); 
        Canvas.SetLeft(bottomControls, bottomLeftControls.ActualWidth + widthTools); 
        Canvas.SetTop(bottomControls, newTopForBottomLeftControls); 
       } 
       else 
       { 
        Canvas.SetLeft(bottomControls, 0); 
        Canvas.SetTop(bottomControls, newTopForBottomLeftControls + bottomLeftControls.ActualHeight + 2); 
       } 

       NudgeWindowToFit(); 
      } 
     } 

     base.OnRenderSizeChanged(sizeInfo); 
    } 


    /// <summary> 
    /// Abstracts the issue of determining size, which is complex now that controls may be moved by OnRenderSizeChanged(). 
    /// </summary> 
    /// At scales of 3 or more, the controls are overlaid on the image. 
    private Size SizeAtScale(int tryScale) 
    { 
     double newWidth = (tryScale * initialBitmapSize.Width) + initialRightSideControlsBounds.Width + fireLegendGrid.Width + 
      initialWindowExtra.Width; 
     double newHeight = (tryScale * initialBitmapSize.Height) + initialWindowExtra.Height; 
     if (tryScale < 4) 
     { 
      // bottomLeftControls are under image 
      newHeight += bottomLeftControls.ActualHeight; 
      if (tryScale < 3) 
      { 
       // and other bottom controls stacked in two rows 
       newHeight += bottomControls.ActualHeight + 2; 
      } 
     } 

     return new Size(newWidth, newHeight); 
    } 


    protected override void OnActivated(EventArgs e) 
    { 
     base.OnActivated(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="#00000000" VerticalAlignment="Top" Width="256" Height="256"/> 
     </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> 
3

UI的目的是有点不清楚,所以我会坚持从给人一种更完整的答案,现在回来了。但是,如果你只是有一个形象,你想覆盖有那么Grid控制该图像的右下角是解决方案: -

<Grid> 
    <Image x:Name="img" Stretch="None" /> 
    <StackPanel x:Name="control" VerticalAlignment="Bottom" HorizontalAlignment="Right"> 
     <!-- controls here --> 
    </StackPanel> 
</Grid> 

该电网将大小到任何尺寸的图片(除非其较小的控制面板),控制面板将浮在图像右下角的顶部。这种情况越少,就越让组件做这项工作。

由于您的控件之一是“缩放”,我怀疑您还有其他问题需要解决,这可能最终导致这个问题没有实际意义,但以上是您现在需要的内容。

0

将Image控件和堆栈面板放置在网格中,并分别将堆栈面板的水平和垂直对齐方式更改为Right和Bottom。我认为这应该可以解决问题。