Ich habe eine WPF-ListBox, mit einem benutzerdefinierten DataTemplate für die ListBox ItemTemplate (jedes Element hat eine Reihe von Steuerelementen; d.h. Textfelder und Datepickers). Ich habe ein Verhalten an die letzte DatePicker, die dem Benutzer erlaubt, ICommand im Event-Handler für ein PreviewKeyDown-Ereignis auszuführen.
Die Idee ist, dass der Benutzer mit der Tabulatortaste die Steuerelemente in der ListBoxItem durchläuft, und wenn er zum letzten Steuerelement gelangt und erneut die Tabulatortaste drückt, wird ein neues ListBoxItem zur ListBox hinzugefügt. Der Fokus wird dann auf das erste Steuerelement in der nächsten ListBoxItem bewegen. Meine Lösung funktioniert gut, wenn sich bereits 2 Elemente in der ListBox befinden und Sie mit der Tabulatortaste durch das erste Element gehen. Wenn es nur 1 Element in der ListBox, und Sie erhalten auf das letzte Steuerelement, das neue ListBoxItem hinzugefügt wird (wie erwartet), aber der Fokus bewegt sich über die ListBox auf die nächste übergeordnete Steuerung.
Es ist, als ob der Verhaltenscode aufgerufen wird und der ICommand aufgerufen wird, aber das TAB-Ereignis geht weiter, ohne darauf zu warten, dass das neue ListBoxItem hinzugefügt wird.
Irgendwelche Vorschläge?
Mein Verhalten (ZBehaviorBase ist nur eine Klasse, die ein "besseres" Aufräumen ermöglicht):
public class TabOffCommandBehavior : ZBehaviorBase<FrameworkElement>
{
public ICommand TabCommand
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("TabCommand", typeof(ICommand), typeof(TabOffCommandBehavior));
protected override void Initialize()
{
this.AssociatedObject.PreviewKeyDown += new KeyEventHandler(AssociatedObject_PreviewKeyDown);
}
protected override void Uninitialize()
{
if (this.AssociatedObject != null)
{
this.AssociatedObject.PreviewKeyDown -= new KeyEventHandler(AssociatedObject_PreviewKeyDown);
}
}
void AssociatedObject_PreviewKeyDown(object sender, KeyEventArgs e)
{
// if you want to pass a command param to CanExecute, need to add another dependency property to bind to
if (TabCommand != null && e.Key == Key.Tab && TabCommand.CanExecute(null))
{
TabCommand.Execute(null);
}
}
XAML:
<ListBox Grid.Row="1" KeyboardNavigation.TabNavigation="Continue" ItemsSource="{Binding Path=OrderLines, Mode=OneWay}"
ItemTemplate="{DynamicResource LineTemplate}" SelectionMode="Extended">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Margin" Value="0,5,0,5"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template" Value="{DynamicResource ListBoxItemTemplate}"/>
<Setter Property="IsEnabled" Value="{Binding Path=IsLocked, Converter={StaticResource NotBoolConverter}}"/>
<Setter Property="IsSelected" Value="{Binding Path=IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
INSIDE "LineTemplate":
<TextBox Grid.Column="9" Grid.Row="3" Text="{Binding Path=SellPriceOverride, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" VerticalAlignment="Center" Margin="5,0" TabIndex="10">
<!--IF ANOTHER INTERACTIVE CONTROL IS ADDED PAST THIS ONE ON THE LINE, THIS COMMENT AND THE BEHAVIOR MUST BE MOVED TO THAT CONTROL INSTEAD-->
<e:Interaction.Behaviors>
<ZViewModels:TabOffCommandBehavior TabCommand="{Binding Path=DataContext.AddNewOrderLine, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"/>
</e:Interaction.Behaviors>
</TextBox>
Das Einzige, was in der "Execute"-Methode des Befehls geschieht, ist, dass ein Objekt zu einer Sammlung hinzugefügt wird, die die ItemSource für die ListBox ist