Расширенное редактирование TDocument блокирует пользовательский интерфейс

#multithreading #caliburn.micro

#многопоточность #caliburn.micro

Вопрос:

Мой Caliburn Micro UI заблокирован из-за довольно сложного набора элементов управления, содержащихся в TDocument. Я пробовал несколько разных асинхронных подходов для переноса действия в другой поток, но безуспешно. Вот упрощенный вид кода. Вы можете распознать его, потому что оно взято из примера приложения Hello Screens.

Чтобы вкратце увидеть, как работает проводник документов, вот интерфейс:

 Public MustInherit Class DocumentWorkspace(Of TDocument As {Class, INotifyPropertyChanged, IDeactivate, IHaveDisplayName})
    Inherits Conductor(Of TDocument).Collection.OneActive
    Implements IDocumentWorkspace

    Protected Sub New()

    Public MustOverride ReadOnly Property Icon As String Implements IWorkspace.Icon
    Public MustOverride Property IconName As String Implements IWorkspace.IconName
    Public Property PixelLabTransitions As BindableCollection(Of Transition)
    Public Property ScreenTransition As Transition
    Public Property State As DocumentWorkspaceState
    Public Property Status As String Implements IWorkspace.Status
    Protected ReadOnly Property Conductor As IConductor

    Public Overrides Sub ActivateItem(item As TDocument)
    Public Sub Edit(child As TDocument)
    Public Sub Hide()
    Public Sub Show() Implements IWorkspace.Show
End Class 
  

Вот код-нарушитель:

                 _SelectedDesignerElement = value
                'adjust Count located next to Icon 
                vm.DisplayName = value.DesignerDisplayText
                count  = 1
                vm.IsDirty = True
                'the next line of code works but 
                'disables the UI for a long time
                Edit(vm)
  

Итак, самый простой способ, которым я могу показать проблему, — попытаться перенести это длительное действие в другой поток:

                 'Plan to show a Busy indicator here

                'Below I have tried to move the edit to another thread
                'but this simply does not work

                Dim t As Task = Task.Factory.StartNew(Sub()
                                                          Edit(vm)
                                                      End Sub)
                t.Wait()


                'Plan to remove Busy indicator here
  

У кого-нибудь есть идея получше, как освободить пользовательский интерфейс для этого затянувшегося процесса?

Кстати, проблема, очевидно, заключается в том, что редактирование (VM) не устраивает в другом потоке, потому что я протестировал тот же подход с индикатором занятости, используя только счетчик для создания задержки, а начальная занятость / конечная занятость работают просто отлично, и пользовательский интерфейс остается отзывчивым.

Ответ №1:

Прозрение произошло после того, как я проснулся посреди ночи. Проект Hello Screens был импортирован в текущую версию Visual Studio (2015), но мне никогда не приходило в голову, что целевая среда останется такой же, как и исходный проект. Таким образом, фреймворк указывал на версию до асинхронной и ожидал поддержки.

Я завершил добавление индикатора занятости в общедоступном домене в Caliburn.Micro Hello отображает пример проекта. Существует несколько различных ситуаций, в которых может возникнуть необходимость в индикаторе занятости, и существует несколько различных способов активации элемента управления. Например, я обнаружил, что место для активации Busy в моем первоначальном вопросе: в DocumentWorkspace, как показано здесь .

     Public Async Sub ShowAsync() Implements HelloScreensWPF.Framework.IWorkspace.ShowAsync
        'Notice that this Sub is Async and the Name is changed from Show (In the CM Sample) to Show Async
        'Not sure this is the very best way but it works pretty good
        'Anytime the user clicks an icon at the bottom of the UI this sub is called
        Dim haveActive = TryCast(Parent, IHaveActiveItem)
        If haveActive IsNot Nothing AndAlso haveActive.ActiveItem Is Me Then
            DisplayName = IconName
            State = DocumentWorkspaceState.Master
        Else
            'We need to have access to the ShellViewModel
            Dim Svm = CType(Parent, ShellViewModel)
            'Activate the Busy indicator

            'The BusyIndicatorViewModel has a built in '200 µ Sec Delay
            'So if it is Deactivated before it 'fires' the user will not see a
            'flash of an unnecessary Busy Indicator
            Svm.ShellBusyIndicator.ShowBusyIndicator(True, True, "Loading", IconName)

            'You will need to push the conductor ActivateItem off to another thread for a real application and
            'get rid of the Sample Task.Delay here
            Await Task.Delay(4000)

            Conductor.ActivateItem(Me)
            Dim list = CType(Parent, IConductor).GetChildren

            'Deactivate Busy Indicator
            Svm.ShellBusyIndicator.ShowBusyIndicator(False)

        End If
    End Sub
  

Если кому-то нужна копия HelloScreens с решением Busy, просто отправьте мне электронное письмо по адресу aqsi.net с помощью @.