XAML: placing controls over the image

I need to display Imagein a cell Grid. In the upper part of the image in the lower right corner of the image, an StackPanelelement of controls should be added (for example, scaling, brightness, etc.). How can this be done. I am doing the following, but not sure how to position the controls StackPanelin the lower right corner of the image. The position must be maintained even if the user resizes the browser window.

<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>
+3
source share
3 answers

, . , , , Grid : -

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

( ), . , , .

- "", , , , , .

+3

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>
0

Image . , .

0

All Articles