我的WPF MVVM VB.NET应用程序在启动时将歌曲列表加载到ListBox中。列表内容填充在ViewModel的构造函数中启动的BackgroundWorker中。完成后,我希望将焦点设置为列表中的第一首歌曲。
由于设置这个焦点纯粹是一个视图操作,我希望它在XAML的代码隐藏中,焦点在哪里与ViewModel无关。
我尝试过在各种窗口和列表框事件上这样做,但是它们要么不触发,要么触发太早。所以我认为我需要的是一个布尔属性,当ViewModel将歌曲加载到列表中时,它会设置该属性。这时我需要View捕捉该属性更改,并调用代码隐藏函数,该函数具有操纵View的逻辑,在这种情况下,将焦点设置在列表中的第一首歌曲上。
但这正是我对WPF了解不足的地方。我搜索了一下,听起来DataTrigger可以做到这一点。但把它放在哪里,什么是正确的语法,以及如何让它调用我的代码隐藏函数呢?
或者有一个更简单的方法,我忽略了。这似乎是一个基本的功能-触发一些代码隐藏的行动时,属性改变了某种方式在视图模型。
下面是代码隐藏函数,一旦它在预期的时间被成功调用,我就可以详细描述它:
Private Sub FocusSongsList()
' set focus back to the Songs list, selected item (couldn't just set focus to the list, it ran forever and looks like it set focus to every item in turn before releasing the UI)
Dim listBoxItem = CType(LstSongs.ItemContainerGenerator.ContainerFromItem(LstSongs.SelectedItem), ListBoxItem)
If Not listBoxItem Is Nothing Then
listBoxItem.Focus()
End If
End Sub
下面是我的列表框:
<ListBox x:Name="LstSongs" ItemsSource="{Binding FilteredSongs}" DisplayMemberPath="Path"
HorizontalAlignment="Stretch"
SelectionMode="Extended" SelectionChanged="LstSongs_SelectionChanged" Loaded="FocusSongsList"/>
我将定义一个新属性,可以从BackgroundWorker的RunWorkerCompleted部分设置该属性。
Private _InitialSongLoadCompleted As Boolean
Public Property InitialSongLoadCompleted() As Boolean
Get
Return _InitialSongLoadCompleted
End Get
Set(ByVal value As Boolean)
_InitialSongLoadCompleted = value
RaisePropertyChanged("InitialSongLoadCompleted")
End Set
End Property
3条答案
按热度按时间o0lyfsai1#
DataTrigger
不能执行方法。它只能设置属性。焦点不能通过设置属性来激活,因此
DataTrigger
不能解决您的问题。一般来说,如果你有长时间运行的初始化例程,你应该把它们移到init例程(可以是
async
)或者使用Lazy<T>
。例如,你示例化你的视图模型类,然后调用Initialize()
。在方法返回后,你可以继续初始化ListBox
:主窗口.xaml.cs
主视图模型.cs
9nvpjoqh2#
我已经很久很久没有写过VB了,所以这是C#代码。
您可以处理在绑定上更新的目标。
当数据从源(viewmodel属性)传输到目标(ui属性,此处为itemssource)时将触发此事件
当你替换你的列表时,targetupdated将被触发。如果你引发属性changed,那么数据将被传输(很明显)。
当数据传输时,最初将没有任何项目,所以我们需要一点延迟。因此,Task.Delay将等待200ms,并应让UI呈现。您可以使其更长一点或dispatcher.invokeasync。
它找到第一个容器,并设置焦点和键盘焦点。项目具有焦点可能一点也不明显。
一个更优雅的方法是使用dispatcher,它可以有效地将聚焦安排到ui呈现之后,但是,对于不熟悉c#的人来说,这可能看起来相当棘手
如果你想要一个蓝色的背景,那么你可以选择该项目.
或者您可以使用一些数据触发器和样式与IsFocused一起工作。
https://learn.microsoft.com/en-us/dotnet/api/system.windows.uielement.isfocused?view=windowsdesktop-7.0
(总是让我分心的是,一个s而不是两个和IsFocussed。这将是美国英语我猜)
这是我的主窗口视图模型
我正在使用社区工具包mvvm来生成代码,也许它可以像c#一样使用vb。
kiayqfof3#
你可以通过在视图模型中定义一个自定义事件来实现你的目标,这个事件在列表处理完成时被触发,视图可以订阅它并相应地采取行动。
它看起来像这样:
你提到了在后台线程上进行处理。我不完全确定完成事件将发送到哪个线程,但要注意UI的东西只能发生在UI线程上,所以你可能需要使用
Dispatcher.Invoke
来确保你的代码在正确的线程上运行。我会这样做来运行RaiseEvent
,这样视图就不需要知道它的任何信息。