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

苏在宇

在 WPF 中,我在画布上创建按钮。像这样。

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;
    }

但是当我运行此代码并扩展应用程序大小时,按钮位置不会更新。

在此处输入图片说明

在此处输入图片说明

第二张图片是扩展的应用程序大小,我创建的小按钮是行为锚定对象。我想这个按钮跟随背景图像。

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>

我怎样才能解决这个问题?

** 更新:添加 TestCode ,修复 Xaml 代码。

这是 wpf 项目的测试代码

  • 背后的代码 -

    public partial class MainWindow : Window
    

    { 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 代码 - => 与 abaove 的 xaml 代码相同。只需将那个停靠面板放在窗口之后。像这个窗口> .. 这里 ../window>

曼特

答案可能有点长,但它应该无需修改即可工作。

基本上:

  • 我为你的 Canvas 添加了一个 SizeChanged 事件
  • 它计算背景图像的大小和位置(旧的和新的)
  • 对于每个按钮,它计算背景图像的相对位置(旧的和新的)并修改它
  • 有很多关于纵横比的事情(以确保正确的行为),并且此代码只能使用统一的行为(Stretch="Uniform")

这是修改后的 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>

然后是后面的代码(在 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);
        }

    }

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在WPF图像中显示位图

来自分类Dev

如何在WPF中覆盖WindowStyle

来自分类Dev

如何在WPF中填充时区

来自分类Dev

如何在Wpf中设置图像的来源?

来自分类Dev

如何在WPF中闪烁标签文本

来自分类Dev

如何在WPF中顺序显示窗口?

来自分类Dev

如何在WPF中的窗口之间导航?

来自分类Dev

WPF如何从后面的代码中的itemspaneltemplate获取画布?

来自分类Dev

如何在视图WPF中创建视图

来自分类Dev

如何在后面的代码中设置DataGrid行的背景颜色?

来自分类Dev

如何在WPF中叠加图像?

来自分类Dev

如何在WPF中启用/禁用按钮

来自分类Dev

如何在WPF中设置CheckBox的BackColor

来自分类Dev

如何在WPF中更改画布的位置?

来自分类Dev

如何在后面的代码中设置框架的高度请求?

来自分类Dev

WPF如何在后面的代码中检索绑定的属性

来自分类Dev

如何在WPF中绑定

来自分类Dev

如何从后面的代码中设置嵌套的数据源?

来自分类Dev

如何在标题栏WPF上放置设置按钮?

来自分类Dev

如何在WPF中设置数据绑定

来自分类Dev

如何在WPF网格上设置样式

来自分类Dev

如何在WPF中隐藏面板后面的项目

来自分类Dev

如何在WPF中更改画布的位置?

来自分类Dev

如何处理在后面的代码中引发WPF Validation.ErrorEvent的需要

来自分类Dev

如何在aspx.cs页面后面的代码中设置as:css样式之前

来自分类Dev

如何在后面的代码中设置视频标签的来源?

来自分类Dev

如何在c#中设置WPF的位置

来自分类Dev

C# WPF 如何在后面的代码中获取绑定值

来自分类Dev

如何在WPF后面的代码中获取`ContentPresenter`中的数据?