[英]How to Bind to Another Control Property in WPF
I am using the WPF Charting ToolKit via the namespaces: 我通过命名空间使用WPF Charting ToolKit:
xmlns:ChartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:VisualizationToolkit="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
I have a chart control in which I generate a random color for each time a Lineseries
plot is undertaken. 我有一个图表控件,每次进行
Lineseries
绘图时我会生成一个随机颜色。 I remove the data point markers and colorize using the following style 我删除数据点标记并使用以下样式着色
<Style x:Key="LineDataPointStyle"
TargetType="ChartingToolkit:LineDataPoint">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Width" Value="NaN"/>
<Setter Property="Height" Value="NaN"/>
<Setter Property="Background"
Value="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource ColorBrushConverter}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ChartingToolkit:LineDataPoint">
<Grid x:Name="Root" Opacity="0"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The LineSeries
is defined via LineSeries
是通过定义的
<ChartingToolkit:LineSeries Title="{Binding DisplayName}"
AnimationSequence="FirstToLast"
SnapsToDevicePixels="True"
DataPointStyle="{StaticResource LineDataPointStyle}"
ItemsSource="{Binding Data}"
IndependentValueBinding="{Binding X}"
DependentValueBinding="{Binding Y}"/>
Now, this works fine but the legend markers display a different color to the random one I generate for the LineSeries
. 现在,这样可以正常工作,但图例标记显示的颜色与我为
LineSeries
生成的随机颜色不同。 I want the same color to be displayed for the legend item for the LineSeries
and the Lineseries
itself. 我想为
LineSeries
和Lineseries
本身的图例项目显示相同的颜色。 So, I have styled the legend item as below 所以,我将传说项目设置如下
<Style x:Key="TestSuiteLegendItemStyle"
TargetType="{x:Type ChartingToolkit:LegendItem}">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ChartingToolkit:LegendItem}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel Orientation="Horizontal">
<Rectangle Width="8"
Height="8"
Fill="{Binding Background}"
Stroke="{Binding BorderBrush}"
StrokeThickness="1" Margin="0,0,3,0" />
<VisualizationToolkit:Title Content="{TemplateBinding Content}" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My question is how can I 'bind' the Rectangle.Fill
in the TestSuiteLegendItemStyle
style so that it is the same color as the LineSeries
as set by the LineDataPointStyle
defined above? 我的问题是如何在
TestSuiteLegendItemStyle
样式中“绑定” Rectangle.Fill
,以便它与LineDataPointStyle
定义的LineDataPointStyle
设置的LineSeries
颜色相同? * *
Thanks for your time. 谢谢你的时间。
Edit. 编辑。 I have tried setting a
DependencyProperty
that holds the Background
color of my plot as suggested below via 我已经尝试设置一个
DependencyProperty
,它保存我的绘图的Background
颜色,如下所示
<Style x:Key="LineDataPointStyle"
TargetType="ChartingToolkit:LineDataPoint">
...
<Setter Property="Background"
Value="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource ColorBrushConverter}}"/>
...
</Style>
Where the I have ammended the converter (as marked) so that I can store the randomly generated background color and then use this in my legend 我已经修改了转换器(标记为),以便我可以存储随机生成的背景颜色,然后在我的图例中使用它
public class ColorToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
Brush b = new SolidColorBrush(Utils.GenerateRandomColor());
MultiChartExtensions.BackgroundBrushProperty = b; <= how to set the dependency property?
return b;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
where the Dependency Property (DP) is defined as 其中依赖属性(DP)定义为
public static readonly DependencyProperty BackgroundBrushProperty;
public static void SetBackgroundBrush(DependencyObject DepObject, Brush value)
{
DepObject.SetValue(BackgroundBrushProperty, value);
}
public static Brush GetBackgroundBrush(DependencyObject DepObject)
{
return (Brush)DepObject.GetValue(BackgroundBrushProperty);
}
I would then look to set the legend background via this DP via 然后我会通过此DP来设置图例背景
<Style x:Key="TestSuiteLegendItemStyle"
TargetType="{x:Type ChartingToolkit:LegendItem}">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ChartingToolkit:LegendItem}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel Orientation="Horizontal">
<Rectangle Width="8"
Height="8"
Fill="{Binding MultiChart:MultiChartExtensions.BackgroundBrushProperty}"
Stroke="{Binding BorderBrush}"
StrokeThickness="1" Margin="0,0,3,0" />
<VisualizationToolkit:Title Content="{TemplateBinding Content}" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Any help with this would be appreciated... 任何有关这方面的帮助将不胜感激......
Part I. Binding in ControlTemplate
If you want to use Binding in a ControlTemplate
, you should use following construction: 如果要在
ControlTemplate
使用Binding ,则应使用以下构造:
<ControlTemplate TargetType="{x:Type SomeControl}">
<Rectangle Fill="{TemplateBinding Background}" />
A
TemplateBinding
is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with{Binding RelativeSource={RelativeSource TemplatedParent}}.
TemplateBinding
是模板场景的绑定的优化形式,类似于使用{Binding RelativeSource={RelativeSource TemplatedParent}}.
构造的{Binding RelativeSource={RelativeSource TemplatedParent}}.
Notes about using TemplateBinding
TemplateBinding
doesn't work outside a template or outside its VisualTree property, so you can't even use TemplateBinding inside a template's trigger. TemplateBinding
在模板外或VisualTree属性之外不起作用,因此您甚至无法在模板的触发器中使用TemplateBinding。 Furthermore, TemplateBinding doesn't work when applied to a Freezable (for mostly artificial reasons), for example - VisualBrush
. 此外,当应用于Freezable时,TemplateBinding不起作用(主要是出于人为原因),例如
VisualBrush
。 In such cases it is possible to use Binding like this: 在这种情况下,可以像这样使用Binding:
<FreezableControl Property="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=Background}" />
Also, you can always use an alternative for TemplateBinding
: 此外,您始终可以使用
TemplateBinding
的替代方法:
<Rectangle Fill="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=Background}" />
As another possibility, you can also try the following: 作为另一种可能性,您还可以尝试以下方法:
<Rectangle Fill="{Binding Background,
RelativeSource={RelativeSource AncestorType={x:Type SomeControl}},
Path=Background}" />
Part II. Notes about your version
In your case, this may cause a conflict of names in the ControlTemplate
, because you already are using Binding background is for Border. 在您的情况下,这可能会导致
ControlTemplate
的名称冲突,因为您已经使用Binding背景是为Border。 Therefore, remove it this Binding for a Border
, or use another property, such as Tag
or attached dependency property for binding Background color. 因此,删除它为
Border
绑定 ,或使用其他属性,如Tag
或附加依赖属性绑定背景颜色。
Example of using
Instead ChartingToolkit
controls, took as a basis Button
control, because it's easier to demonstrate the idea of this styles. 取而代之的是
ChartingToolkit
控件,作为Button
控件的基础,因为它更容易展示这种样式的想法。
Solution 1: using Tag
<Window.Resources>
<Style x:Key="TestButtonStyle" TargetType="{x:Type Button}">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<!-- Here we are set Tag for Border Background -->
<Border Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Rectangle Width="24"
Height="24"
Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"
Stroke="{TemplateBinding BorderBrush}" />
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button Name="TestButton"
Style="{StaticResource TestButtonStyle}"
Content="Test"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Tag="Green"
Background="Aquamarine"
Width="100"
Height="100" />
</Grid>
Output
Here for Rectangle
, set two colors: default for Rectangle
, in Tag for Border
. 对于
Rectangle
,设置两种颜色: Rectangle
默认值,Tag for Border
。 I do not find this a good solution, and here's why: 我觉得这不是一个好的解决方案,原因如下:
If a Border and Rectangle need to set different values, such as: Background, BorderThickness, BorderBrush, etc. one Tag
is not enough. 如果Border和Rectangle需要设置不同的值,例如:Background,BorderThickness,BorderBrush等,则一个
Tag
是不够的。
With one name property must be clearly its purpose, one name "Tag" us to nothing says. 有一个名称属性必须明确其目的,一个名称“标记”我们什么也没说。
Of these disadvantages can be concluded that we should find an alternative, as an alternative I use a extender-class with the attached dependency properties. 在这些缺点中可以得出结论,我们应该找到一个替代方案,作为替代方案,我使用带有附加依赖属性的扩展类。
Extender class ButtonExt.cs
扩展程序类
ButtonExt.cs
public static class ButtonExt
{
#region RectangleBackground Property
public static readonly DependencyProperty RectangleBackgroundProperty;
public static void SetRectangleBackground(DependencyObject DepObject, Brush value)
{
DepObject.SetValue(RectangleBackgroundProperty, value);
}
public static Brush GetRectangleBackground(DependencyObject DepObject)
{
return (Brush)DepObject.GetValue(RectangleBackgroundProperty);
}
#endregion
#region RectangleBorderBrush Property
public static readonly DependencyProperty RectangleBorderBrushProperty;
public static void SetRectangleBorderBrush(DependencyObject DepObject, Brush value)
{
DepObject.SetValue(RectangleBorderBrushProperty, value);
}
public static Brush GetRectangleBorderBrush(DependencyObject DepObject)
{
return (Brush)DepObject.GetValue(RectangleBorderBrushProperty);
}
#endregion
#region Button Constructor
static ButtonExt()
{
#region RectangleBackground
PropertyMetadata BrushPropertyMetadata = new PropertyMetadata(Brushes.Transparent);
RectangleBackgroundProperty = DependencyProperty.RegisterAttached("RectangleBackground",
typeof(Brush),
typeof(ButtonExt),
BrushPropertyMetadata);
#endregion
#region RectangleBorderBrush
RectangleBorderBrushProperty = DependencyProperty.RegisterAttached("RectangleBorderBrush",
typeof(Brush),
typeof(ButtonExt),
BrushPropertyMetadata);
#endregion
}
#endregion
}
MainWindow.xaml
<Window.Resources>
<Style x:Key="TestButtonExtensionStyle" TargetType="{x:Type Button}">
<Setter Property="Width" Value="80" />
<Setter Property="Height" Value="80" />
<Setter Property="Background" Value="Green" />
<Setter Property="BorderBrush" Value="Pink" />
<Setter Property="BorderThickness" Value="4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Rectangle Fill="{TemplateBinding PropertiesExtension:ButtonExt.RectangleBackground}"
Stroke="{TemplateBinding PropertiesExtension:ButtonExt.RectangleBorderBrush}"
Width="30"
Height="30" />
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button Style="{StaticResource TestButtonExtensionStyle}"
PropertiesExtension:ButtonExt.RectangleBackground="Aquamarine"
PropertiesExtension:ButtonExt.RectangleBorderBrush="Black"
Content="Test" />
</Grid>
Output
Part III. Setting values for dependency properties
When you create and register your attached dependency property, you must declare the Set and Get methods to work with him: 创建并注册附加的依赖项属性时,必须声明Set和Get方法与他一起使用:
public static void SetRectangleBackground(DependencyObject DepObject, Brush value)
{
DepObject.SetValue(RectangleBackgroundProperty, value);
}
public static Brush GetRectangleBackground(DependencyObject DepObject)
{
return (Brush)DepObject.GetValue(RectangleBackgroundProperty);
}
Then work with them will be as follows: 然后与他们合作将如下:
Set
ButtonExt.SetRectangleBackground(MyButton, Brushes.Red);
Get
Brush MyBrush = ButtonExt.GetRectangleBackground(MyButton);
But in our case, it's not so simple. 但就我们而言,并非如此简单。 When I used the attached dependency property problems in updating values were not.
当我使用附加的依赖属性问题时,更新值不是。 But in our case, the property is in the template, and in my case there was no update
Button
. 但在我们的例子中,属性在模板中,在我的情况下没有更新
Button
。 I tried to set Mode=TwoWay
, UpdateSourceTrigger=PropertyChanged
, in Binding and in the property declaration, GetBindingExpression().UpdateTarget()
, but it was useless. 我试图在Binding和属性声明中设置
Mode=TwoWay
, UpdateSourceTrigger=PropertyChanged
, GetBindingExpression().UpdateTarget()
,但它没用。
Note that for the property setting a new value, and notification from the template is not, that the property has been updated. 请注意,对于属性设置新值和模板的通知,属性已更新。 Maybe I'm wrong, and you have will work, or maybe it's made specifically, for example to avoid memory leaks.
也许我错了,你会工作,或者可能是专门制作的,例如为了避免内存泄漏。
In any case, it is better not to update the dependency property directly, and bind to it the property of the Model
and in the ViewModel
to set the value. 在任何情况下,最好不要直接更新依赖属性,并将
Model
的属性绑定到它,并在ViewModel
中设置值。
Example: 例:
<Button Style="{StaticResource TestButtonExtensionStyle}"
adp:ButtonExt.RectangleBackground="{Binding Path=Model.RectBackground,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
adp:ButtonExt.RectangleBorderBrush="{Binding Path=Model.RectBorderBrush,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
where RectBackground
and RectBorderBrush
implement the INotifyPropertyChanged
interface. 其中
RectBackground
和RectBorderBrush
实现INotifyPropertyChanged
接口。
As an alternative in this case, do not use dependency properties and use the DataTemplate
for the control. 作为这种情况的替代方法,不要使用依赖项属性并使用
DataTemplate
作为控件。 DataTemplate
ideal for MVVM, very flexible and dynamic. DataTemplate
是MVVM的理想选择,非常灵活和动态。
For example, work with DataTemplate
, you can see my answers: 例如,使用
DataTemplate
,您可以看到我的答案:
Make (create) reusable dynamic Views 创建(创建)可重用的动态视图
One ViewModel for UserControl and Window or separate ViewModels 一个用于UserControl和Window的ViewModel或单独的ViewModel
Set x:Name
on LineSeries control: 在LineSeries控件上设置
x:Name
:
<ChartingToolkit:LineSeries x:Name="lineSeries"/>
Then you can bind in TestSuiteLegendItemStyle
via binding using ElementName
: 然后,您可以使用
ElementName
通过绑定绑定TestSuiteLegendItemStyle
:
<Rectangle Fill="{Binding Background, ElementName=lineSeries}"/>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.