我为用户创建了一个AddressInput控件来输入地址。根据它的使用位置,控件将具有不同的外观,因此我提供了一个名为AddressTemplate的DataTemplate属性。
默认样式如下所示:
<Style TargetType="{x:Type addressUI:AddressInput}">
<Setter Property="AddressTemplate"
Value="{StaticResource DefaultAddressTemplate}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type addressUI:AddressInput}">
<GroupBox Header="Address">
<ContentPresenter ContentTemplate="{Binding Path=AddressTemplate, RelativeSource={RelativeSource TemplatedParent}}"
Content="{Binding Path=Address, RelativeSource={RelativeSource TemplatedParent}}"
x:Name="PART_AddressPresenter" />
</GroupBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我的所有地址数据模板都将包含一个用于选择国家/地区的组合框(名为“PART_CountriesList”)。我需要在选择更改时触发一些代码隐藏操作,这意味着我需要挂钩SelectionChanged事件。在我的AddressInput中,我需要在AddressTemplate中找到PART_CountriesList。
我可以像这样得到“PART_AddressPresenter”ContentPresenter:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var addressPresenter = Template.FindName("PART_AddressPresenter", this) as ContentPresenter;
}
现在如何在AddressTemplate中包含“PART_CountriesList”?
我试过了:
var countriesList = AddressTemplate.FindName(“PART_CountriesList”,addressPresenter);
抛出异常是因为addressPresenter尚未应用其模板。我知道ContentPresenter具有OnApplyTemplate覆盖,但为此用途扩展它似乎很愚蠢。
我想如果我要扩展ContentPresenter,我会创建一个新的可重用版本,只要OnApplyTemplate方法执行就会触发事件。这可能会解决我的问题,但似乎很疯狂。还有更好的方法吗?
答案 0 :(得分:0)
我很好奇是否有人有“正确”的方式来做这件事,但是使用FindName我总是诉诸于这样的事情:
Dispatcher.BeginInvoke( new Action(() =>
{
// Call FindName here
}), System.Windows.Threading.DispatcherPriority.Render );
这可能会导致闪烁,因为你要等到数据模板化完成并渲染后才能运行你的代码,所以如果你要做的事情会影响控件的外观,这并不总是很好选项。