WPF取消带有消息框的选项卡选择

时间:2018-08-20 22:19:51

标签: wpf multithreading tabcontrol selectionchanged

当用户尝试移至新选项卡时,我需要检测到脏页面,并为用户提供取消移出当前选项卡的选项。当我不需要询问用户时,我可以使它工作,但是显示消息框会破坏功能。我提供了一个显示问题的简单应用程序。抱歉,它在VB中,但这就是我们在这里使用的。

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ChangeTab"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <TabControl SelectedIndex="{Binding SelectedIndex}" Initialized="TabControl_Initialized" IsSynchronizedWithCurrentItem="True">
        <TabItem Header="Tab 1">
            <TextBlock Text="Content 1"/>
        </TabItem>
        <TabItem Header="Tab 2">
            <StackPanel>
                <TextBlock Text="Content 2"/>
                <CheckBox Content="Locked" IsChecked="{Binding IsChecked}"/>
            </StackPanel>
        </TabItem>
    </TabControl>
</Window>

Imports System.ComponentModel
Imports System.Windows.Threading

Class MainWindow
    Implements INotifyPropertyChanged
    Dim tc As TabControl

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    Public Function SetProperty(Of T)(ByRef storage As T, value As T, PropertyName As String) As Boolean
        If Object.Equals(storage, value) Then Return False
        storage = value
        NotifyPropertyChanged(PropertyName)
        Return True
    End Function

    Public Sub NotifyPropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(propertyName))
    End Sub

    Private _IsChecked As Boolean
    Public Property IsChecked As Boolean
        Get
            Return _IsChecked
        End Get
        Set(value As Boolean)
            SetProperty(_IsChecked, value, "IsChecked")
        End Set
    End Property

    Private _SelectedIndex As Integer
    Public Property SelectedIndex As Integer
        Get
            Return _SelectedIndex
        End Get
        Set(value As Integer)
            SetProperty(_SelectedIndex, value, "SelectedIndex")
        End Set
    End Property

    Private Sub TabControl_Initialized(sender As Object, e As EventArgs)
        tc = DirectCast(sender, TabControl)
        AddHandler tc.Items.CurrentChanging, AddressOf Items_CurrentChanging
    End Sub

    Private Sub Items_CurrentChanging(sender As Object, e As CurrentChangingEventArgs)
        Dim Result As MessageBoxResult
        If SelectedIndex = 0 And IsChecked Then
            Result = MessageBox.Show("Do you want to leave this tab?", "Leave", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No, MessageBoxOptions.ServiceNotification)
            If Result = MessageBoxResult.No Then
                e.Cancel = True
                tc.SelectedItem = DirectCast(sender, ICollectionView).CurrentItem
            End If
        End If
    End Sub
End Class

如果您运行此应用并按照以下步骤操作,则会发现标签页控件停止响应标签页更改。

1. Click TAB 2 (we move to TAB 2)
2. Check the Locked checkbox
3. Click TAB 1
4. Respond NO to the popup (we stay on TAB 2)
5. Click TAB 1 again
6. Response YES to the popup (we return to TAB 1)
7. Click TAB 2 again (we move to TAB 2)
8. Click on TAB 1
9. Response NO to the popup (we stay on TAB 2)
10. Click on TAB 1 again -- nothing happens!

注意:如果清除并选中“锁定”复选框,则功能将返回。 如果在Items_CurrentChanging中放置一个断点,则一切正常。当然,这是一个线程问题-谁能告诉我哪里出了问题,更重要的是,如何解决它?

谢谢

1 个答案:

答案 0 :(得分:0)

似乎没有引发Items_CurrentChanging事件,因为我单击的选项卡仍然具有焦点(即使它不是当前项目)。我不知道为什么我们必须经历两次迭代才能看到问题。解决方案是在设置SelectedIndex之后添加一行代码。这会将焦点重新设置到我们没有离开的标签上。

Dispatcher.BeginInvoke(Sub() DirectCast(tc.SelectedItem, UIElement).Focus())

如果有人可以照亮这里发生的事情,我将非常感激。