我已经设置了一个简单的示例来尝试实现一个简单的事情:在自定义控件中公开依赖项属性,该控件公开此自定义控件中控件的ActualWidth / ActualHeight。
为了实现我的目标:
customcontrol.cs
public class CustomControl : ContentControl
{
static CustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
}
public static readonly DependencyProperty RenderedWidthProperty = DependencyProperty.Register(
"RenderedWidth", typeof (double), typeof (CustomControl), new PropertyMetadata(default(double)));
public double RenderedWidth
{
get { return (double) GetValue(RenderedWidthProperty); }
set { SetValue(RenderedWidthProperty, value); }
}
public static readonly DependencyProperty RenderedHeightProperty = DependencyProperty.Register(
"RenderedHeight", typeof (double), typeof (CustomControl), new PropertyMetadata(default(double)));
public double RenderedHeight
{
get { return (double) GetValue(RenderedHeightProperty); }
set { SetValue(RenderedHeightProperty, value); }
}
}
generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Custom_Control_Pushing_ActualWidth">
<Style TargetType="{x:Type local:CustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl}">
<Grid local:SizeObserver.Observe="True"
local:SizeObserver.ObservedWidth="{Binding RenderedWidth, RelativeSource={RelativeSource TemplatedParent}}"
local:SizeObserver.ObservedHeight="{Binding RenderedHeight, RelativeSource={RelativeSource TemplatedParent}}">
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
viewmodel.cs
class ViewModel
{
private double width;
private double height;
public double Width
{
get { return width; }
set
{
width = value;
Console.WriteLine("Width: {0}", value);
}
}
public double Height
{
get { return height; }
set
{
height = value;
Console.WriteLine("Height: {0}", value);
}
}
}
mainwindow.xaml
<Window x:Class="Custom_Control_Pushing_ActualWidth.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Custom_Control_Pushing_ActualWidth"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Grid>
<local:CustomControl RenderedWidth="{Binding Width, Mode=OneWayToSource}" RenderedHeight="{Binding Height, Mode=OneWayToSource}" />
</Grid>
</Window>
我使用this SO answer中的SizeObserver。
然而,虽然我看到依赖项属性中的代码在size观察者中被更新,但绑定的viewmodel属性的setter不会被设置为值。我的绑定有问题,我不知道它是什么。
如何正确地将DependencyProperty与ViewModel的属性绑定?
答案 0 :(得分:1)
改变这个:
<Grid local:SizeObserver.Observe="True"
local:SizeObserver.ObservedWidth="{Binding RenderedWidth, RelativeSource={RelativeSource TemplatedParent}}"
local:SizeObserver.ObservedHeight="{Binding RenderedHeight, RelativeSource={RelativeSource TemplatedParent}}">
</Grid>
对此:
<Grid local:SizeObserver.Observe="True"
local:SizeObserver.ObservedWidth="{Binding RenderedWidth, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWayToSource}"
local:SizeObserver.ObservedHeight="{Binding RenderedHeight, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWayToSource}">
</Grid>
因此将Mode=OneWayToSource
添加到绑定的末尾。
这样,ViewModel中的Width属性正在为我正确更新。
背后的原因对我来说并不完全清楚,但我认为ObservedWidth
和ObservedHeight
附加属性的默认绑定模式是OneWay。因此,只有在源属性(ObservedWidth, ObservedHeight
)发生更改时,它们才会更新目标属性(RenderedWidth, RenderedHeight
)。
你想要完全相反。
通过OneWayToSource
修改,ActualWidth
和ActualHeight
属性中的更改将很好地传播到您的ViewModel。