2011-05-22 44 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。我認爲這應該可以解決問題。