wpf 将路径填充绑定到 ContentPresenter 中的按钮前景
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19720532/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Binding Path Fill to Button Foreground in ContentPresenter
提问by user1084857
I have a Button Style with a Template containing a ContentPresenter, in which I am attempting to bind the Fill of a Path to the Foreground of a button:
我有一个带有包含 ContentPresenter 的模板的按钮样式,我试图在其中将路径的填充绑定到按钮的前景:
<!-- This is inside the template of a button style -->
<ContentPresenter>
<ContentPresenter.Resources>
<Style TargetType="{x:Type Path}">
<Setter Property="Fill" Value="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
I also have a Path with no Fill set, that I can reference in the button as the content, like so:
我还有一个没有设置填充的路径,我可以在按钮中引用它作为内容,如下所示:
<Button Style="{DynamicResource MyButtonStyle}" Content="{DynamicResource PathIcon}" Foreground="Blue"/>
I would expect the Path inside the button to be blue, but it isn't... it doesn't grab the foreground from the button.
我希望按钮内的 Path 是蓝色的,但它不是......它不会从按钮上抓取前景。
How can I get the Path to bind to the color of the button?
如何让路径绑定到按钮的颜色?
Thank you!
谢谢!
P.S.:
PS:
If I put a hardcoded color in the Value (i.e. Value="Red"), the Path inside the button is red... so I know that works...
如果我在值中添加硬编码颜色(即 Value="Red"),则按钮内的 Path 是红色的......所以我知道这有效......
<ContentPresenter>
<ContentPresenter.Resources>
<Style TargetType="{x:Type Path}">
<Setter Property="Fill" Value="Red"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
Edit:
编辑:
Here is the complete Style and ControlTemplate:
这是完整的 Style 和 ControlTemplate:
<Style x:Key="Button_Style" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{StaticResource White_Brush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="grid" Background="Transparent">
<ContentPresenter>
<ContentPresenter.Resources>
<Style TargetType="{x:Type Path}">
<Setter Property="Fill" Value="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!-- Should affect Text as well as Paths in the Content property of the button! -->
<Setter Property="Foreground" Value="{StaticResource Black_Brush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
回答by Anatoliy Nikolaev
Okay, let's order:
好的,让我们订购:
it doesn't grab the foreground from the button.
它不会从按钮中获取前景。
In styles this construction:
在这种结构的样式中:
RelativeSource={RelativeSource AncestorType=Button}
will not work, because the Styleis just the collection of setters, he does not know about control, are there, specifically about the content of the visual tree. Because RelativeSourceshould refer to the items abovein the visual tree. For this purpose, usually using DataTemplateor ControlTemplate.
行不通,因为这Style只是setter的集合,他不知道控制,有没有,特别是关于可视化树的内容。因为RelativeSource应该参考上面可视化树中的项目。为此,通常使用DataTemplate或ControlTemplate。
If I put a hardcoded color in the Value (i.e. Value="Red")
如果我在 Value 中添加了硬编码颜色(即 Value="Red")
Yes, in this case, will be working, and always better to create the design of the form:
是的,在这种情况下,将起作用,并且总是更好地创建表单设计:
<SolidColorBrush x:Key="MyButtonColor" Color="Blue" />
And use it for control, like Button:
并将其用于控制,例如Button:
<Button Background="{StaticResource MyButtonColor}" ... />
and in Styleor elsewhere:
在Style或其他地方:
<Setter Property="Fill" Value="{StaticResource MyButtonColor}" />
That is, it is better not to depend on the element parameters (background color, etc.) located in a visual tree, because it can:
也就是说,最好不要依赖位于可视化树中的元素参数(背景颜色等),因为它可以:
- May move to another panel (
Grid,StackPanel) orUserControl - May leave from the project
- 可以移动到另一个面板 (
Grid,StackPanel) 或UserControl - 可以离开项目
And brushes in the as resources will always be in one place, changing them in this place, all the elements of their pick up. Also colors can be stored in a special data model that does not depend on the specific technical implementations (resources, variables) in which the data can come from an external source, such as the project/config settings.
而刷子中的资源会一直在一个地方,改变它们在这个地方,它们的所有元素都捡起来。此外,颜色可以存储在不依赖于特定技术实现(资源、变量)的特殊数据模型中,其中数据可以来自外部源,例如项目/配置设置。
If possible, it is better to avoid the use of dynamic resources due to unnecessary use of system perfomance (and in some cases memory leaks), in your cases they are not needed.
如果可能,最好避免由于不必要地使用系统性能(以及在某些情况下内存泄漏)而使用动态资源,在您的情况下不需要它们。
Dynamic resources are usually explicitly defined for SolidColorBrushand another species brushes, because by default they are frozen, and they not recommended changed because of the above mentioned reasons (memory leaks). More information can be found here:
动态资源通常是为SolidColorBrush其他种类的笔刷明确定义的,因为默认情况下它们是冻结的,并且由于上述原因(内存泄漏)不建议更改它们。更多信息可以在这里找到:
Freezable Objects Overview on MSDN
Edit
Edit
As I understand it, you want to make universal Stylefor Buttonto make the contents of Pathor Text(in the case of simultaneous use will be easier). As I have already mentioned above, RelativeSourceshould be around ControlTemplate, therefore, the Pathwill be in the Gridwith the ContentPresenter.
据我了解,你想使通用Style为Button使内容Path或Text(在同时使用的情况下会更容易)。正如我上面已经提到的,RelativeSource应该在 附近ControlTemplate,因此,Path将Grid与ContentPresenter.
To style knew, which is provided for the text or for the path, to the Tag(optional property) indicates two properties: OnlyTextor OnlyPath.
为文本或路径提供的样式知道,到Tag(可选属性)表示两个属性:OnlyText或OnlyPath。
To set the data for the Path, I've created a attacheddependency property, and prescribed it in the ControlTemplate.
为了设置 的数据Path,我创建了一个附加的依赖属性,并在ControlTemplate.
Below is a complete example:
下面是一个完整的例子:
XAML
XAML
<Window x:Class="ButtonPathHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ButtonPathHelp"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<SolidColorBrush x:Key="Green_Brush" Color="Green" />
<SolidColorBrush x:Key="Black_Brush" Color="Black" />
<Style x:Key="Button_Style" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{StaticResource Green_Brush}" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="grid">
<ContentPresenter x:Name="MyContent"
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}" />
<Path x:Name="MyPath"
SnapsToDevicePixels="True"
Width="20"
Height="18"
Stretch="Fill"
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
Data="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:MyDependencyClass.DataForPath)}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{StaticResource Black_Brush}"/>
</Trigger>
<Trigger Property="Tag" Value="OnlyText">
<Setter TargetName="MyPath" Property="Visibility" Value="Collapsed" />
<Setter TargetName="MyContent" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="Tag" Value="OnlyPath">
<Setter TargetName="MyPath" Property="Visibility" Value="Visible" />
<Setter TargetName="MyContent" Property="Visibility" Value="Collapsed" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<WrapPanel>
<WrapPanel.Resources>
<sys:String x:Key="Save">
F1 M 20.5833,20.5833L 55.4167,20.5833L 55.4167,55.4167L 45.9167,55.4167L 45.9167,44.3333L 30.0833,44.3333L 30.0833,
55.4167L 20.5833,55.4167L 20.5833,20.5833 Z M 33.25,55.4167L 33.25,50.6667L 39.5833,50.6667L 39.5833,55.4167L 33.25,
55.4167 Z M 26.9167,23.75L 26.9167,33.25L 49.0833,33.25L 49.0833,23.75L 26.9167,23.75 Z
</sys:String>
<sys:String x:Key="Search">
F1 M 23.4454,49.2637L 31.7739,41.1598C 30.6986,39.2983 30.4792,37.1377 30.4792,34.8333C 30.4792,27.8377 35.7544,
22.1667 42.75,22.1667C 49.7456,22.1667 55.4167,27.8377 55.4167,34.8333C 55.4167,41.8289 49.7456,47.1042 42.75,
47.1042C 40.5639,47.1042 38.5072,46.9462 36.7125,45.9713L 28.3196,54.1379C 27.0829,55.3746 24.6821,55.3746 23.4454,
54.1379C 22.2088,52.9013 22.2088,50.5004 23.4454,49.2637 Z M 42.75,26.9167C 38.3777,26.9167 34.8333,30.4611 34.8333,
34.8333C 34.8333,39.2056 38.3777,42.75 42.75,42.75C 47.1222,42.75 50.6667,39.2056 50.6667,34.8333C 50.6667,
30.4611 47.1222,26.9167 42.75,26.9167 Z
</sys:String>
</WrapPanel.Resources>
<Button Name="SaveButton"
Style="{StaticResource Button_Style}"
Tag="OnlyPath"
local:MyDependencyClass.DataForPath="{StaticResource Save}"
Margin="10" />
<Button Name="JustText"
Style="{StaticResource Button_Style}"
Tag="OnlyText"
Content="Just Text"
Margin="10" />
<Button Name="SearchButton"
Style="{StaticResource Button_Style}"
Tag="OnlyPath"
local:MyDependencyClass.DataForPath="{StaticResource Search}"
Margin="10" />
</WrapPanel>
</Window>
Code behind
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MyDependencyClass : DependencyObject
{
#region IsCheckedOnDataProperty
public static readonly DependencyProperty DataForPathProperty;
public static void SetDataForPath(DependencyObject DepObject, string value)
{
DepObject.SetValue(DataForPathProperty, value);
}
public static string GetDataForPath(DependencyObject DepObject)
{
return (string)DepObject.GetValue(DataForPathProperty);
}
#endregion
static MyDependencyClass()
{
PropertyMetadata MyPropertyMetadata = new PropertyMetadata(String.Empty);
DataForPathProperty = DependencyProperty.RegisterAttached("DataForPath",
typeof(string),
typeof(MyDependencyClass),
MyPropertyMetadata);
}
}
Note:In the StyleI have not used TemplateBinding for attached property, because TemplateBinding doesn't work outside a template or outside its VisualTree property, so you can't even use TemplateBinding inside a template's trigger. Therefore, we must use the construction {RelativeSource TemplatedParent}and a Path equal to the dependency property whose value you want to retrieve.
Note:在Style我没有将 TemplateBinding 用于附加属性,因为 TemplateBinding 在模板之外或其 VisualTree 属性之外不起作用,所以您甚至不能在模板的触发器内使用 TemplateBinding。因此,我们必须使用与{RelativeSource TemplatedParent}要检索其值的依赖属性相同的构造和 Path。
Output
Output


To download the entire example please follow this link.
要下载整个示例,请点击此链接。
回答by Robert K
I stumbled across simillar problem but was wondering how to get to the 'Foreground Colour' of the Button in its DISABLED state (to have correct colour of my drawing). Here is a finally simple sollution. No templates, No styles, no code, nothing at all. Just the right relative binding :-) :
我偶然发现了类似的问题,但想知道如何在禁用状态下获得按钮的“前景颜色”(以获得正确的绘图颜色)。这是一个最终的简单解决方案。没有模板,没有样式,没有代码,什么都没有。恰到好处的相对绑定:-):
<StackPanel Orientation="Horizontal">
<Button Height="22" IsEnabled="False">
<Polygon Points="4,0 4,5 5,5 2.5,10 0,5 1,5 1,0 "
Fill="{Binding (TextElement.Foreground), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}}">
<Polygon.LayoutTransform>
<RotateTransform Angle="90"></RotateTransform>
</Polygon.LayoutTransform>
</Polygon>
</Button>
<Button Height="22" IsEnabled="True">
<Polygon Points="4,0 4,5 5,5 2.5,10 0,5 1,5 1,0 "
Fill="{Binding (TextElement.Foreground), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}}">
<Polygon.LayoutTransform>
<RotateTransform Angle="180"></RotateTransform>
</Polygon.LayoutTransform>
</Polygon>
</Button>
</StackPanel>

