WPF:依赖属性和 DataContext
我正在致力于在 WPF 中创建可重用的自定义控件(不是用户控件)。我在 Themes/Generic.xaml 文件中创建了 XAML,并在控件的 CS 文件中设置了“lookless”功能:
AddressField.cs
using ...;
namespace MyNamespace
{
[TemplatePart(Name = AddressField.ElementAddress1TextBox, Type = typeof(TextBox))]
public class AddressField : Control
{
private const String ElementAddress1TextBox = "PART_Address1TextBox";
public AddressEntity Address
{
get { return (AddressEntity)GetValue(AddressProperty); }
set { SetValue(AddressProperty, value); }
}
public static readonly DependencyProperty AddressProperty =
DependencyProperty.Register("Address", typeof(AddressEntity), typeof(AddressField), new UIPropertyMetadata(null, new PropertyChangedCallback(OnAddressPropertyChangedCallback)));
static AddressField()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AddressField), new FrameworkPropertyMetadata(typeof(AddressField)));
}
}
}
Themes\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:MyNamespace"
>
<Style TargetType="{x:Type local:AddressField}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AddressField}">
<StackPanel>
<Grid x:Name="StandardView">
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Height" Value="17" />
<Setter Property="Margin" Value="3,3,3,3" />
</Style>
<Style TargetType="TextBox">
<Setter Property="Height" Value="23" />
<Setter Property="Margin" Value="3,3,3,3" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Address 1, Address2-->
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Text="Address:" TextWrapping="NoWrap" />
<TextBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="8" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MinWidth="300"
x:Name="PART_Address1TextBox" Text="{Binding Path=Address1}" />
</Grid>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Form.xaml
<Window x:Class="NIC.BackOffice.Casino.RegistrationEntryForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:nic="clr-namespace:MyNamespace;assembly=MyStuff">
<Canvas>
<nic:AddressField Canvas.Left="10" Canvas.Top="10"
x:Name="OfficeAddressField" Address={Binding Path=OAddress} />
</Canvas>
</Window>
Form.cs
using ...;
namespace MyNamespace
{
public partial class Form : Window
{
public Form()
{
InitializeComponent();
OAddress = new AddressEntity("1234 Testing Lane");
}
public AddressEntity OAddress { get; set; }
}
}
更新:之前的代码是我之前代码的更新(删除了很多废话只是为了了解一个示例)。但是,由于某种原因,即使我将 OAddress 绑定到 AddressField 对象,地址(在 OfficeAddressField 内)也永远不会更新。
I was working on creating a reusable custom control (not a user control) in WPF. I created the XAML in the Themes/Generic.xaml file and I setup the "lookless" functionality in the control's CS file:
AddressField.cs
using ...;
namespace MyNamespace
{
[TemplatePart(Name = AddressField.ElementAddress1TextBox, Type = typeof(TextBox))]
public class AddressField : Control
{
private const String ElementAddress1TextBox = "PART_Address1TextBox";
public AddressEntity Address
{
get { return (AddressEntity)GetValue(AddressProperty); }
set { SetValue(AddressProperty, value); }
}
public static readonly DependencyProperty AddressProperty =
DependencyProperty.Register("Address", typeof(AddressEntity), typeof(AddressField), new UIPropertyMetadata(null, new PropertyChangedCallback(OnAddressPropertyChangedCallback)));
static AddressField()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AddressField), new FrameworkPropertyMetadata(typeof(AddressField)));
}
}
}
Themes\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:MyNamespace"
>
<Style TargetType="{x:Type local:AddressField}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AddressField}">
<StackPanel>
<Grid x:Name="StandardView">
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Height" Value="17" />
<Setter Property="Margin" Value="3,3,3,3" />
</Style>
<Style TargetType="TextBox">
<Setter Property="Height" Value="23" />
<Setter Property="Margin" Value="3,3,3,3" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Address 1, Address2-->
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Text="Address:" TextWrapping="NoWrap" />
<TextBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="8" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MinWidth="300"
x:Name="PART_Address1TextBox" Text="{Binding Path=Address1}" />
</Grid>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Form.xaml
<Window x:Class="NIC.BackOffice.Casino.RegistrationEntryForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:nic="clr-namespace:MyNamespace;assembly=MyStuff">
<Canvas>
<nic:AddressField Canvas.Left="10" Canvas.Top="10"
x:Name="OfficeAddressField" Address={Binding Path=OAddress} />
</Canvas>
</Window>
Form.cs
using ...;
namespace MyNamespace
{
public partial class Form : Window
{
public Form()
{
InitializeComponent();
OAddress = new AddressEntity("1234 Testing Lane");
}
public AddressEntity OAddress { get; set; }
}
}
UPDATED: The prior code is an update from my previous code (removed a lotta fluff just to get down to the ONE example). Though, for some reason Address (within OfficeAddressField) is never ever updated even though I set the binding of OAddress to the AddressField object.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您不需要刷新
DataContext
。事实上,您的控件不应该使用它。将Address
设为DependencyProperty
,然后在控件模板中使用TemplateBinding
:You don't need to refresh the
DataContext
. In fact, your control shouldn't be using it. MakeAddress
aDependencyProperty
and then use aTemplateBinding
in your control's template:您应该考虑在地址 dp 更改时引发事件。
You should consider raising an event when the address dp changes.