我正在编写一个 WPF 输入对话框窗口,它将基于名为 InputType 的依赖属性显示不同的控件。我使用的语言是 Visual COBOL .NET,但问题与语言无关,而与 WPF 本身有关,VB 和 C# 程序员很容易理解该语言。这是我的对话窗口的 XAML 代码
<Window x:Name="wndDialog"
x:Class="ClassLibraryNew.AGInputBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lib="clr-namespace:ClassLibraryNew"
xmlns:ctrl="clr-namespace:ClassLibraryNew.Controls"
Width="400"
MinHeight="200"
WindowStyle="None"
WindowStartupLocation="CenterOwner"
ResizeMode="NoResize"
Background="#FFEEEEEE"
SizeToContent="Height"
MouseDown="OnMouseDown"
Loaded="OnLoaded">
<Window.CommandBindings>
<CommandBinding Command="{x:Static lib:DialogCommands.OkCommand}" CanExecute="OnCommandCanExecute" Executed="OnCommandExecuted"/>
<CommandBinding Command="{x:Static lib:DialogCommands.CancelCommand}" CanExecute="OnCommandCanExecute" Executed="OnCommandExecuted"/>
</Window.CommandBindings>
<Border Style="{StaticResource AGTWindowBorder}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="{Binding Caption}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Text="{Binding Text}"
FontSize="{Binding Converter={StaticResource FontSizeConverter}, ConverterParameter='16'}"
VerticalAlignment="Center"
TextWrapping="Wrap"/>
<ContentControl Grid.Row="1" x:Name="contentControl" >
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Foreground="Red" Text="Errore: input type non valido. Contattare l'assistenza tecnica."/>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding InputType}" Value="Text">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ctrl:TextField Text="{Binding Value, ElementName=wndDialog}"
ctrl:WatermarkService.Watermark="{Binding WatermarkText, ElementName=wndDialog}"
ctrl:WatermarkService.HideWhenFocused="False"
MaxLength="{Binding MaxLength, ElementName=wndDialog}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding InputType}" Value="Integer">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ctrl:IntegerField Value="{Binding Value, ElementName=wndDialog}"
ZeroFill="{Binding ZeroFill, ElementName=wndDialog}"
MaxLength="{Binding MaxLength, ElementName=wndDialog}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding InputType}" Value="Decimal">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ctrl:DecimalField Value="{Binding Value, ElementName=wndDialog}"
DecimalDigits="{Binding DecimalDigits, ElementName=wndDialog}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
</GroupBox>
<StackPanel Grid.Row="1"
Orientation="Horizontal"
HorizontalAlignment="Right"
Margin="8">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource EuroButton}">
<Setter Property="Width" Value="80"/>
<Setter Property="Margin" Value="8,0,0,0"/>
</Style>
</StackPanel.Resources>
<Button IsDefault="True"
Command="{x:Static lib:DialogCommands.OkCommand}">
<AccessText Text="_Ok"/>
</Button>
<Button IsCancel="True"
Command="{x:Static lib:DialogCommands.CancelCommand}">
<AccessText Text="_Annulla"/>
</Button>
</StackPanel>
</Grid>
</Border>
我想要实现的是当 InputType 为 Text 时向用户显示“TextField”(自定义 TextBox),当 InputType 为 Integer 时向用户显示“IntegerField”等。 InputType 的类型是一个枚举名称 DialogInputType,其中包含三个值(Text、Integer , 十进制)。这工作正常,但是我需要一种方法来将事件处理程序附加到 ContentControl 内的字段,当其内容已正确设置且不为空时。我希望 DataTriggers 在 InputType 更改时重新评估,而不是失败:(Visual COBOL .NET)
01 InputTypeProperty type DependencyProperty public static initialize only
value type DependencyProperty::Register(
"InputType",
type of DialogInputType,
type of AGInputBox,
new FrameworkPropertyMetadata(
type DialogInputType::Text,
new PropertyChangedCallback(method OnInputTypeChanged)
)
).
*> property definition omitted...
method-id OnInputTypeChanged private static.
procedure division using by value sender as type DependencyObject, by value e as type DependencyPropertyChangedEventArgs.
if sender not instance of type AGInputBox
goback
end-if
declare wnd as type AGInputBox = sender as type AGInputBox
if wnd::contentControl::Content instance of type FieldBase *> debugger arrives here
declare textField as type FieldBase
set textField = wnd::contentControl::Content as type FieldBase
attach method wnd::OnFieldTemplateApplied to textField::TemplateApplied
end-if
end method.
VS调试器显示ContentControl的Content为null,但随后窗口被正确可视化,可能它的内容稍后设置......它也是null: - 窗口的加载事件 - 窗口的ContentRendered事件 我可以'不要在 DataTemplate 控件内设置 Loaded RoutedEventHandler,无论是使用 Loaded="OnFieldLoaded" 还是使用 Style + EventSetter,因为它被禁止并且不会编译(即使编译器错误建议使用 EventSetter :/)。
编辑:我尝试了 l33t 的解决方案,但不幸的是 OnContentChanges 永远不会被调用,即使内容设置正确。我创建了这个类:
class-id ClassLibraryNew.Controls.NotifyingContentControl public
inherits type ContentControl.
01 ContentChanged type EventHandler event public.
method-id new public.
procedure division.
invoke super::new()
end method.
method-id OnContentChanged protected override.
procedure division using by value oldContent as object, by value newContent as object.
invoke super::OnContentChanged(oldContent, newContent) *> I put a debugger breakpoint here but it's not getting hit
invoke RaiseContentChanged()
end method.
method-id RaiseContentChanged private.
procedure division.
declare handler as type EventHandler = ContentChanged
declare e as type EventArgs = new EventArgs()
if handler not = null
invoke run handler(by value self, e)
end-if
end method.
end class.