如何取消 WPF TabControl 中的选项卡更改

2024-02-02

我在 SO 上发现了有关此问题的多个问题,但是我仍然无法完全获得可靠的解决方案。这是我在阅读答案后得出的结论。

Xaml:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="300" Width="300" x:Name="this">
    <TabControl IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Tabs, ElementName=this}" x:Name="TabControl"/>
</Window>

背后代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        var tabs = new ObservableCollection<string> {"Tab1", "Tab2", "Tab3"};
        Tabs = CollectionViewSource.GetDefaultView(tabs);
        Tabs.CurrentChanging += OnCurrentChanging;
        Tabs.CurrentChanged += OnCurrentChanged;
        Tabs.MoveCurrentToFirst();
        CurrentTab = tabs.First();
    }

    private void OnCurrentChanging(object sender, CurrentChangingEventArgs e)
    {
        //only show message box when tab is changed by user input
        if (!_cancelTabChange)
        {
            if (MessageBox.Show("Change tab?", "Message", MessageBoxButton.YesNo) == MessageBoxResult.No)
            {
                _cancelTabChange = true;
                return;
            }
        }
        _cancelTabChange = false;
    }

    private void OnCurrentChanged(object sender, EventArgs e)
    {
        if (!_cancelTabChange)
        {
            //Update current tab property, if user did not cancel transition
            CurrentTab = (string)Tabs.CurrentItem;
        }
        else
        {
            //navigate back to current tab otherwise
            Dispatcher.BeginInvoke(new Action(() => Tabs.MoveCurrentTo(CurrentTab)));
        }
    }

    public string CurrentTab { get; set; }

    public static readonly DependencyProperty TabsProperty = DependencyProperty.Register("Tabs", typeof(ICollectionView), typeof(MainWindow), new FrameworkPropertyMetadata(default(ICollectionView)));
    public ICollectionView Tabs
    {
        get { return (ICollectionView)GetValue(TabsProperty); }
        set { SetValue(TabsProperty, value); }
    }

    private bool _cancelTabChange;
}

基本上,当用户导航到不同的选项卡时,我想显示一条确认消息,如果他单击“否”,则中止转换。但这段代码不起作用。如果您多次单击“Tab2”,每次在消息框中选择“否”,则在某个时刻它会停止工作:事件停止触发。如果您单击“Tab3”,事件将再次触发,但如果您选择“是”,它将打开第二个选项卡,而不是第三个选项卡。我无法弄清楚到底发生了什么。 :)

有人看到我的解决方案中存在错误吗?或者当用户切换选项卡时是否有更简单的方法来显示确认消息?我也愿意使用任何开源选项卡控件,它确实有一个适当的SelectionChanging事件。但我找不到任何东西。

我正在使用.Net 4.0。

Edit:如果我评论消息框:

private void OnCurrentChanging(object sender, CurrentChangingEventArgs e)
{
    //only show message box when tab is changed by user input
    if (!_cancelTabChange)
    {
        //if (MessageBox.Show("Change tab?", "Message", MessageBoxButton.YesNo) == MessageBoxResult.No)
        //{
            Debug.WriteLine("Canceled");
            _cancelTabChange = true;
            return;
        //}
    }
    _cancelTabChange = false;
}

一切正常。诡异的。


这个解决方案来自网络档案 https://web.archive.org/web/20210120155559/http://coderelief.net/2011/11/07/fixing-issynchronizedwithcurrentitem-and-icollectionview-cancel-bug-with-an-attached-property/

似乎配合得很好

<TabControl ... yournamespace:SelectorAttachedProperties.IsSynchronizedWithCurrentItemFixEnabled="True" .../>

private void OnCurrentChanging(object sender, CurrentChangingEventArgs e)
{                   
    if (MessageBox.Show("Change tab?", "Message", MessageBoxButton.YesNo) == MessageBoxResult.No)
    {
        e.Cancel = true;                    
    }                     
}



public static class SelectorAttachedProperties
{
    private static Type _ownerType = typeof(SelectorAttachedProperties);
 
    #region IsSynchronizedWithCurrentItemFixEnabled
 
    public static readonly DependencyProperty IsSynchronizedWithCurrentItemFixEnabledProperty =
        DependencyProperty.RegisterAttached("IsSynchronizedWithCurrentItemFixEnabled", typeof(bool), _ownerType,
        new PropertyMetadata(false, OnIsSynchronizedWithCurrentItemFixEnabledChanged));
 
    public static bool GetIsSynchronizedWithCurrentItemFixEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsSynchronizedWithCurrentItemFixEnabledProperty);
    }
 
    public static void SetIsSynchronizedWithCurrentItemFixEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsSynchronizedWithCurrentItemFixEnabledProperty, value);
    }
 
    private static void OnIsSynchronizedWithCurrentItemFixEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Selector selector = d as Selector;
        if (selector == null || !(e.OldValue is bool && e.NewValue is bool) || e.OldValue == e.NewValue)
            return;
 
        bool enforceCurrentItemSync = (bool)e.NewValue;
        ICollectionView collectionView = null;
 
        EventHandler itemsSourceChangedHandler = null;
        itemsSourceChangedHandler = delegate
        {
            collectionView = selector.ItemsSource as ICollectionView;
            if (collectionView == null)
                collectionView = CollectionViewSource.GetDefaultView(selector);
        };
 
        SelectionChangedEventHandler selectionChangedHanlder = null;
        selectionChangedHanlder = delegate
        {
            if (collectionView == null)
                return;
 
            if (selector.IsSynchronizedWithCurrentItem == true && selector.SelectedItem != collectionView.CurrentItem)
            {
                selector.IsSynchronizedWithCurrentItem = false;
                selector.SelectedItem = collectionView.CurrentItem;
                selector.IsSynchronizedWithCurrentItem = true;
            }
        };
 
        if (enforceCurrentItemSync)
        {
            TypeDescriptor.GetProperties(selector)["ItemsSource"].AddValueChanged(selector, itemsSourceChangedHandler);
            selector.SelectionChanged += selectionChangedHanlder;
        }
        else
        {
            TypeDescriptor.GetProperties(selector)["ItemsSource"].RemoveValueChanged(selector, itemsSourceChangedHandler);
            selector.SelectionChanged -= selectionChangedHanlder;
        }
    }
 
    #endregion IsSynchronizedWithCurrentItemFixEnabled
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何取消 WPF TabControl 中的选项卡更改 的相关文章

  • 不同提供商的相同 EDMX 文件

    我正在开发一个项目 其中有一个本地数据库 SQL CE 在不存在与服务器的连接的情况下用作缓冲区 在服务器上我想使用相同的数据库布局 当然 我想使用服务器和客户端上可用的 Common dll 中的相同 EDMX 文件 在客户端中 我有一个
  • 获取 TextBox 中的文本行数

    我试图通过标签显示文本框中的文本行数 但是 问题是如果最后一行为空 标签必须显示没有空行的行号 例如 如果它们有 5 行 最后一行为空 则标签应将行数显示为 4 Thanks private void txt CurrentVinFilte
  • 使用sqlbulkcopy之前如何创建表

    我有一个 DBF 文件 我正在尝试导入该文件 然后将其写入 SQL 表 我遇到的问题是 如果我使用 SqlBulkCopy 它需要我提前创建表 但在我的场景中这是不可能的 因为 dbf 文件不断变化 到目前为止 这是我的代码 public
  • C# - Visual Studio 中的 System.OutOfMemoryException

    我遇到问题 当我右键单击 Visual Studio 中的主窗体并转到 视图设计器 时 出现错误 它说 引发了 System OutOfMemoryException 类型的异常 堆栈跟踪 at System Reflection Asse
  • 当 foreach 块的内容具有 Conditional 属性时,C# 编译器是否会对其进行优化?

    我正在工作中编写一些调试代码 我想知道我所做的是否会损害性能 让我们看一下代码 foreach var item in aCollection Debug WriteLine item Name 我知道 Debug 类使用 Conditio
  • ASMX Web 服务,测试表单仅在本地计算机上适用于一种 WebMethod

    我有一个正在测试的 ASMX WebService 并且在大多数方法上我都可以使用测试表单进行测试 然而 我确实有一种方法 测试表上写着 The test form is only available for requests from t
  • 尽管浮点数相同,但它们并不相等? [复制]

    这个问题在这里已经有答案了 下面的程序输出This No is not same 当两个数字相同时为什么会这样做 void main float f 2 7 if f 2 7 printf This No is same else prin
  • 如何将 Visual-Studio 2010 切换到 c++11

    我是 c 编程新手 我想尝试 c 11 新功能 那么我要问的是如何切换 Visual studio 2010 才能编译 c 11 源代码 你可以参考这个表 VC10 中的 C 0x 核心语言功能 表格 http blogs msdn com
  • c 使用 lseek 以相反顺序复制文件

    我已经知道如何从一开始就将一个文件复制到另一个文件 但是我如何修改程序以按相反的顺序复制它 源文件应具有读取访问权限 目标文件应具有读写执行权限 我必须使用文件控制库 例如 FILE A File B should be ABCDEF FE
  • 使用默认行为将模型绑定到接口

    我正在尝试将控制器操作绑定到接口 但仍保持默认的绑定行为 public class CoolClass ISomeInterface public DoSomething get set ISomeInterface public clas
  • 应用新设置时如何防止 GraphicsDevice 被丢弃?

    我的游戏窗口允许手动调整大小 这意味着它可以像任何其他普通窗口一样通过拖动其边缘来调整大小 游戏还利用了RenderTarget2D rt2d 在主 Draw 方法中设置主渲染目标 GraphicsDevice SetRenderTarge
  • C#生成的csv文件通过电子邮件发送嵌入到Lotus Note中电子邮件的底部

    我遇到了一个奇怪的问题 即使用 NET SmtpClient 通过电子邮件发送的 CSV 附件出现在电子邮件底部 而不是 Lotus Note 中的附件 我只是不知道如何解决这个问题 而且我无法访问客户端计算机 这使得调试非常困难 我可以采
  • 从 Golang 调用 C 函数

    我想在 Golang 中编写控制器逻辑并处理 json 和数据库 同时在 C 中使用我的数学处理模型 在我看来 调用 C 函数的开销必须尽可能低 就像设置寄存器 rcx rdx rsi rdi 一样 执行一些操作fastcall 并获取 r
  • Web 文本编辑器中的 RTF 格式

    网络上是否有支持 RTF 格式文档输入的文本编辑器 我知道这对 webdev 来说有点奇怪 但我需要从数据库中读取 RTF 文档 并在基于 Web 的文本编辑器中对其进行编辑 然后将其存储回 RTF 中 在我在转换工具上投入太多资金之前 我
  • 重定向 std::cout

    我需要一个类 在其对象的生命周期内将一个 ostream 重定向到另一个 ostream 经过一番修补后 我想出了这个 include
  • 如果我重新分配并且新大小为 0,会发生什么情况。这与释放等效吗?

    给出以下代码 int a NULL a calloc 1 sizeof a printf d n a a realloc a 0 printf d n a return 0 它返回 4078904 0 这个 realloc 相当于 free
  • 何时分离或加入 boost 线程?

    我有一个方法 大约每 30 秒触发一次 我需要在一个线程中包含它 我有一个可以从类外调用的方法 像 call Threaded Method 这样的东西会创建一个线程 该线程本身会调用最终的线程方法 这些是 MyClass 的方法 void
  • 确定相关词的编程方式?

    使用网络服务或软件库 我希望能够识别与词根相关的单词 例如 座位 和 安全带 共享词根 座位 但 西雅图 不会被视为匹配 简单的字符串比较对于这类事情似乎是不可行的 除了定义我自己的字典之外 是否有任何库或 Web 服务不仅可以返回单词定义
  • XCode std::thread C++

    对于学校的一个小项目 我需要创建一个简单的客户端 服务器结构 它将在路由器上运行 使用 openWRT 并且我试图在这个应用程序中使用线程做一些事情 我的 C 技能非常有限 所以我在internet https stackoverflow
  • 如何使 WinForms UserControl 填充其容器的大小

    我正在尝试创建一个多布局主屏幕应用程序 我在顶部有一些按钮链接到应用程序的主要部分 例如模型中每个实体的管理窗口 单击这些按钮中的任何一个都会在面板中显示关联的用户控件 面板包含用户控件 而用户控件又包含用户界面 WinForms User

随机推荐