简体   繁体   English

如何在WPF后面的代码中相对设置按钮位置

[英]How set button position relatively in code behind on WPF

In WPF , i create button on canvas. 在WPF中,我在画布上创建按钮。 like this. 像这样。

private void DrawBtnTag( List<ValPosCrt> tagPos) 
    {
        int posNum = tagPos.Count;

        StackPanel[] temp = new StackPanel[ posNum ];
        Button[] btn = new Button[posNum];

        for ( int i = 0 ; i < posNum ; i++ )
        {
            var btntemp = CheckButton(i);
            Canvas.SetLeft( btntemp , tagPos [ i ].X );
            Canvas.SetTop( btntemp , tagPos [ i ].Y );
            cvsMap.Children.Add( btntemp );
            btn [ i ] = btntemp;
        }
    }

    private Button CheckButton( int i ) // done 
    {
        var btn = new Button();
        btn.Name = "btn" + i.ToString();
        btn.Width = 20;
        btn.Height = 20;
        btn.VerticalAlignment = VerticalAlignment.Stretch;
        btn.HorizontalAlignment = HorizontalAlignment.Stretch;
        btn.Click += ClickIdx;
        return btn;
    }

but when i run this code and expand application size, button position is not updated. 但是当我运行此代码并扩展应用程序大小时,按钮位置不会更新。

在此处输入图片说明

在此处输入图片说明

Second image is expanded application size and small button that i created is act anchored object. 第二个图像是扩展的应用程序大小,而我创建的小按钮是作为锚定对象。 I want to this button follow background Image. 我要此按钮跟随背景图像。

Xaml code is just only this XAML代码仅仅是这样

     <DockPanel Name="dckPanel" Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <Border CornerRadius="6" BorderThickness="2" BorderBrush="RoyalBlue" DockPanel.Dock="Top" >
        <Grid>
            <Canvas Name="cvsMap" Grid.Column="0" ClipToBounds="True" Margin="15">
                <Canvas.Background>
                    <ImageBrush x:Name="imgMap" Stretch="Uniform"  RenderOptions.BitmapScalingMode="Fant"   />
                </Canvas.Background>
            </Canvas>
        </Grid>
    </Border>
</DockPanel>

How can i fix this? 我怎样才能解决这个问题?

** update : Add TestCode , Fix Xaml Code. **更新:添加TestCode,修复Xaml代码。

This is test code for wpf project 这是WPF项目的测试代码

  • Code Behind - 背后的代码-

     public partial class MainWindow : Window 

    { public MainWindow() { InitializeComponent(); {public MainWindow(){InitializeComponent();

      List<Point> inputdata = new List<Point>(); inputdata.Add( new Point( 250 , 250 ) ); inputdata.Add( new Point( 250 , 300 ) ); inputdata.Add( new Point( 300 , 250 ) ); inputdata.Add( new Point( 250 , 200 ) ); inputdata.Add( new Point( 200 , 250 ) ); DrawBtnTag( inputdata ); imgMap.ImageSource = createImg(); } private void DrawBtnTag( List<Point> tagPos ) // done { int posNum = tagPos.Count; StackPanel[] temp = new StackPanel[ posNum ]; Button[] btn = new Button[posNum]; for ( int i = 0 ; i < posNum ; i++ ) { var btntemp = CheckButton(i); Canvas.SetLeft( btntemp , tagPos [ i ].X ); Canvas.SetTop( btntemp , tagPos [ i ].Y ); cvsMap.Children.Add( btntemp ); btn [ i ] = btntemp; } } private Button CheckButton( int i ) // done { var btn = new Button(); btn.Name = "btn" + i.ToString(); btn.Width = 20; btn.Height = 20; btn.VerticalAlignment = VerticalAlignment.Stretch; btn.HorizontalAlignment = HorizontalAlignment.Stretch; return btn; } public BitmapSource createImg() { List<System.Windows.Media.Color> colors = new List<System.Windows.Media.Color>(); colors.Add( System.Windows.Media.Colors.Red ); colors.Add( System.Windows.Media.Colors.Blue ); BitmapPalette palette = new BitmapPalette(colors); System.Windows.Media.PixelFormat pf = System.Windows.Media.PixelFormats.Indexed1; int width = 128; int height = width; int stride = width/pf.BitsPerPixel; byte[] pixels = new byte[height*stride]; for ( int i = 0 ; i < height * stride ; ++i ) { if ( i < height * stride / 2 ) { pixels [ i ] = 0x00; } else { pixels [ i ] = 0xff; } } return BitmapSource.Create( width, height, 96, 96, pf, palette, pixels, stride); } 

    } }

  • xaml code - => same as xaml code abaove. xaml代码-=>与xaml代码abaove相同。 just put that dockpanel after window. 只是将那个面板放置在窗口之后。 like this window> .. here ../window> 像这个窗口> ..这里../ window>

The answer might be a bit long but it should work without modifications. 答案可能会有点长,但无需修改即可使用。

Basically: 基本上:

  • I added a SizeChanged event for your Canvas 我为您的Canvas添加了SizeChanged事件
  • It computes the size and position (old and new) for your background image 它计算背景图像的大小和位置(旧的和新的)
  • For each button, it computes the relative position (old and new) from the background image and modifies it 对于每个按钮,它都会根据背景图像计算相对位置(旧的和新的)并对其进行修改
  • There is a lot of things around aspect ratio (to ensure a proper behavior), and this code can work only with a uniform behavior (Stretch="Uniform") 宽高比周围有很多东西(以确保正确的行为),并且此代码只能在一致的行为下工作(Stretch =“ Uniform”)

Here is the modified XAML code: 这是修改后的XAML代码:

<Canvas Name="cvsMap" Grid.Column="0" ClipToBounds="True" Margin="15" SizeChanged="cvsMap_SizeChanged">
    <Canvas.Background>
        <ImageBrush x:Name="imgMap" Stretch="Uniform"  RenderOptions.BitmapScalingMode="Fant"   />
    </Canvas.Background>
</Canvas>

And then the code behind (copy/paste after your createImg function): 然后是后面的代码(在createImg函数之后复制/粘贴):

    private void cvsMap_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        double ratio = imgMap.ImageSource.Width / imgMap.ImageSource.Height;

        foreach (Control ctrl in cvsMap.Children)
        {
            if (ctrl is Button)
            {
                newBtnPosition((Button)ctrl, ratio, e);
            }
        }
    }
    /// <summary>
    /// Assign a new position to a ctrl contained into a canvas
    /// </summary>
    /// <param name="ctrl">control to modify</param>
    /// <param name="ratio">ratio of the reference element</param>
    /// <param name="e">SizeChanged of the container</param>
    private void newBtnPosition(Control ctrl, double ratio, SizeChangedEventArgs e)
    {

        //Everythong is computed according to the reference element (ImageBrush)
        Size oldImgSize, newImgSize;

        //Avoid dividing by 0
        if (e.PreviousSize.Width * e.PreviousSize.Height * e.NewSize.Width * e.NewSize.Height == 0) { return; }

        oldImgSize = RefSize(ratio, e.PreviousSize);
        newImgSize = RefSize(ratio, e.NewSize);

        Point oldImgPos, newImgPos;
        oldImgPos = new Point((e.PreviousSize.Width - oldImgSize.Width) / 2, (e.PreviousSize.Height - oldImgSize.Height) / 2);
        newImgPos = new Point((e.NewSize.Width - newImgSize.Width) / 2, (e.NewSize.Height - newImgSize.Height) / 2);

        //Retrieve the position of the control according to the ref element
        Point ctrlPos = new Point((double)ctrl.GetValue(Canvas.LeftProperty) - oldImgPos.X,
                                 (double)ctrl.GetValue(Canvas.TopProperty) - oldImgPos.Y);

        //Compute the new position according to the reference element
        ctrlPos.X*=newImgSize.Width / oldImgSize.Width;
        ctrlPos.Y *= newImgSize.Height / oldImgSize.Height;

        //Assign the new position according to the Canvas
        ctrl.SetValue(Canvas.LeftProperty, ctrlPos.X + newImgPos.X);
        ctrl.SetValue(Canvas.TopProperty, ctrlPos.Y + newImgPos.Y);
    }

    /// <summary>
    /// Compute a element size, given a aspect ratio, a container size, and a Stretch="Uniform" behavior
    /// </summary>
    /// <param name="ratio">aspect ratio of the control</param>
    /// <param name="containerSize">container size of the control</param>
    /// <returns>new size</returns>
    private Size RefSize(double ratio, Size containerSize)
    {
        double cH, cW;
        cW = containerSize.Width;
        cH = containerSize.Height;

        if (cH * cW == 0) { return new Size(0, 0); }

        if (cW / cH  > ratio)
        {
            return new Size(cH * ratio, cH);
        }
        else
        {
            return new Size(cW, cW/ratio);
        }

    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM