[英]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: 基本上:
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.