如何在 WPF 按钮内绘制尺寸适合控件的形状或线条,而不导致按钮永远扩展?
我快速谷歌了一下,并快速浏览了 StackOverflow,但找不到其他人遇到过这个问题。
我想创建一个带有小 X 的关闭按钮。关闭按钮将执行诸如当您将鼠标悬停在包含它的项目上时淡入和淡出、当您将鼠标悬停在其上时改变颜色以及所有常见的 WPF 可爱功能等操作。最重要的是,这似乎并不那么困难,但在我到达这个阶段之前,我遇到了最奇怪的问题之一。
这是我的按钮的 XAML 样式:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TabCloseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Content">
<Setter.Value>
<Grid>
<Line Stroke="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
X1="0"
Y1="0"
X2="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth, Mode=OneWay}"
Y2="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualHeight, Mode=OneWay}"/>
<Line Stroke="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
X1="0"
Y1="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualHeight, Mode=OneWay}"
X2="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth, Mode=OneWay}"
Y2="0"/>
</Grid>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
我创建了我的按钮,只是作为测试,如下所示:
<Window x:Class="WpfTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="124" Width="569">
<Grid Background="#2b3c59">
<StackPanel Orientation="Horizontal">
<!-- Other controls removed for clarity -->
<Button Style="{DynamicResource TabCloseButtonStyle}"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Padding="2"
Margin="0, 10, 0, 0"
MinWidth="50"
MinHeight="50"></Button>
</StackPanel>
</Grid>
</Window>
这就是一切出现严重错误的地方。当您运行应用程序时,按钮将水平和垂直无限扩展,一次一个像素,直到达到窗口的高度。
现在我可以理解为什么会发生这种情况:线条实际上超出网格的宽度和高度一个单位,导致网格扩展一个单位,然后进行重新布局,数据绑定导致线条重新绘制,无限循环。
因此,为了尝试解决这个问题,我决定在网格中放置一个,但是无论我对 HorizontalAlignment 和 VerticalAlignment 做什么,我最终都会得到 Canvas 和 Grid 的宽度和高度为零,这意味着我不这样做不要接受我的十字架,这非常令人恼火。如果我绑定到按钮的 ActualWidth 和 ActualHeight 属性,我最终会得到一个左上角位于按钮中心的 X。
有人知道我能做些什么来解决这个问题吗?我将非常感谢任何指点 - WPF 对我来说仍然是一个相当新的野兽。
谢谢!
I had a quick Google, and a quick look around StackOverflow, but couldn't find anyone else who'd run into this problem.
I want to create a close button with a little X in it. The close button will do things like fade in and out when you're hovering over the item containing it, change colour when you mouse over, and all the usual WPF loveliness. Bottom line, it doesn't seem like it should be that difficult, but I'm running into one of the weirdest issues ever before I've even got to this stage.
Here's my XAML style for the button:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TabCloseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Content">
<Setter.Value>
<Grid>
<Line Stroke="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
X1="0"
Y1="0"
X2="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth, Mode=OneWay}"
Y2="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualHeight, Mode=OneWay}"/>
<Line Stroke="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
X1="0"
Y1="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualHeight, Mode=OneWay}"
X2="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth, Mode=OneWay}"
Y2="0"/>
</Grid>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And I create my button, just as a test, like this:
<Window x:Class="WpfTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="124" Width="569">
<Grid Background="#2b3c59">
<StackPanel Orientation="Horizontal">
<!-- Other controls removed for clarity -->
<Button Style="{DynamicResource TabCloseButtonStyle}"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Padding="2"
Margin="0, 10, 0, 0"
MinWidth="50"
MinHeight="50"></Button>
</StackPanel>
</Grid>
</Window>
And here's where it all goes horribly wrong. When you run the application the button will expand infinitely, one pixel at a time, horizontally, and vertically until it hits the height of the window.
Now I can understand why this is happening: the Lines actually go one unit beyond the width and height of the Grid causing the Grid to expand by one unit, then there's a relayout, the data binding causes the lines to redraw, ad infinitum.
So, to try and deal with this I decided to put a in the grid but then, no matter what I do with HorizontalAlignment and VerticalAlignment, I end up with both the Canvas and the Grid having zero width and height, which means I don't get my cross, which is massively irritating. If I bind to the ActualWidth and ActualHeight properties of the button I just end up with an X that has the top-left corner centred on the centre of the button.
Does anybody have any idea at all what I can do to fix this? I'd be extremely grateful for any pointers - WPF is still a rather new beast to me.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您不必仅仅为了进行布局而诉诸绑定。正如您所看到的,绑定和布局系统不能协同工作(我认为数据绑定优先于布局,但在您的情况下,布局会导致另一个数据绑定)
您应该能够获得一个非常漂亮的、可拉伸的 X a 只是一个路径:
如果您希望它随按钮大小缩放而不是拉伸(缩放影响明显的笔画宽度),那么只需使用
ViewBox
You shouldn't have to resort to bindings just to do layout. As you've seen, the bindings and the layout systems don't work in concert (I think databinding gets priority over layout, but in your case, layout causes another databinding)
You should be able get quite a nice looking, stretchable X with a just a Path:
If you want it to scale with the button size instead of stretch (scale affects apparent stroke width), then just use a
ViewBox
我建议使用 Stretch 和 Margin 或 Padding 属性,而不是绑定,如下所示
Update
因此,您的示例的问题似乎是最小高度和最小高度。宽度。如果你不能只使用高度和宽度,我建议如下
Instead of binding, I'd suggest using the Stretch and Margin or Padding properties, like the following
Update
So the problem with your example seems to be the min height & width. If you can't just use height & width, I'd suggest something like the following
谢谢大家。事实证明,Rob 使用
Viewbox
的解决方案就是答案。即使我从 MainWindow.xaml 中的 Button 声明中删除MidWidth
和MinHeight
属性,该按钮的行为也很完美。这是我修改后的风格:
再次感谢所有建议!
Thanks everyone. Rob's solution with the
Viewbox
turned out to be the answer. The button behaves perfectly, even if I remove theMidWidth
andMinHeight
attributes from the Button declaration in MainWindow.xaml.Here's my modified style:
Thanks again for all the suggestions!