C# - 如何禁用WPF表单上的所有事件

时间:2018-01-24 15:23:43

标签: c# .net wpf events

我的应用程序中有很多ToggleSwitchCombobox控件,我在应用程序启动时设置它们,它会触发与这些控件关联的所有事件。

这些事件只有在用户与控件交互时才会触发,而不是以编程方式更改值时触发。

有没有办法禁用所有事件并在之后重新激活它们?

我在其他帖子或互联网上找不到任何有效的解决方案。

3 个答案:

答案 0 :(得分:4)

正如有些人所说的那样,这种糟糕的建筑气味,你甚至想要首先做到这一点,但有一种方法可以阻止"阻止"使用if语句和简单布尔值的事件。

首先,您要在班级中声明一个字段。

private bool _blockHandlers;

一旦你完成了这个,你只需要将bool设置为true,你就可以在你的类构造函数中直接启动阻塞处理程序。由于我不知道你班级的名字,我不会去那里。

但是假设你有一个事件处理程序

private void SomeHandler
{
    if (blockHandlers) 
    {
        return;
    }

    // It's not blocked, lets continue...
}

这样,您可以临时阻止处理程序或永久阻止它们,使用此方法您只需检查它们是否被阻止,如果不是,您可以继续使用处理程序。

答案 1 :(得分:0)

禁用所有事件是不可能的,因为框架中有许多事件处理程序,您无法直接控制。您想要这样做的事实表明您的设计存在缺陷。

您可以通过一些管道检测用户交互和程序化更改之间的差异,并尽可能在重要的地方使用它。假设您有ComboBox,并且想要检测用户何时触发SelectionChanged。这可以通过标志来完成,仅在进行程序化更改时设置。即。

private bool blockHandlers;

// Wrapped in a method for convenience.
public void SetSelectedIndex(int index)
{
    blockHandlers = true;
    comboBox.SelectedIndex = index;
    blockHandlers = false;
}

private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (blockHandlers) return;

    // Your event handling code...
}

使用此技术要求始终使用SetSelectedIndex或围绕程序化更改设置/重置blockHandlers,以确保事件处理程序观察它并且什么也不做。< / p>

答案 2 :(得分:0)

我为这个问题想出了更优雅的解决方案。

我创建了以下助手类:

public class WpfEventExecutor
{

    bool isLoaded = false;
    bool isProcessingEvent = false;

    public void SetLoaded()
    {
        isLoaded = true;
    }

    public void Execute(Action action)
    {
        if (!isLoaded) return;
        if (isProcessingEvent) return;
        isProcessingEvent = true;
        action();
        isProcessingEvent = false;
    }
}

GeneralView.xaml:

<Page x:Class="MyApp.UI.Settings.Views.GeneralView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:ui="http://schemas.modernwpf.com/2019"
      xmlns:local="clr-namespace:MyApp.UI.Settings.Views"
      mc:Ignorable="d"
      Title="GeneralItem">

    <StackPanel>

        <ui:ToggleSwitch Name="StartWithWindowsCheckbox" Toggled="StartWithWindowsCheckbox_OnToggled" Header="Start with Windows" />

        <Line Height="20" />

        <TextBlock>Language</TextBlock>
        <ComboBox Margin="0,10,0,0">
            <ComboBoxItem Selected="EnglishBoxItem_OnSelected" Name="EnglishBoxItem">English</ComboBoxItem>
            <ComboBoxItem Selected="ChineseBoxItem_OnSelected" Name="ChineseBoxItem">简体中文</ComboBoxItem>
        </ComboBox>

    </StackPanel>
</Page>

GeneralView.cs:

using System.Windows;
using MyApp.Helpers;
using Page = System.Windows.Controls.Page;

namespace MyApp.UI.Settings.Views
{
    /// <summary>
    /// Interaction logic for GeneralItem.xaml
    /// </summary>
    public partial class GeneralView : Page
    {
        
        readonly WpfEventExecutor eventExecutor = new WpfEventExecutor();

        public GeneralView()
        {
            InitializeComponent();

            StartWithWindowsCheckbox.IsOn = LogicHelpers.IsStartWithWindows();


            switch (MyApp.Settings.Values.General.Language)
            {
                case MyApp.Settings.GeneralType.LanguageType.English:
                    EnglishBoxItem.IsSelected = true;
                    break;
                case MyApp.Settings.GeneralType.LanguageType.Chinese:
                    ChineseBoxItem.IsSelected = true;
                    break;
            }

            // Call this method only after you finished to change the elements programmatically
            // After calling to this method, we assume that each time the elements values changed,
            // it caused by the user and not via code
            eventExecutor.SetLoaded();

        }



        void StartWithWindowsCheckbox_OnToggled(object sender, RoutedEventArgs e)
        {
            eventExecutor.Execute(() =>
            {
                // This is safe section where to process the event.
                // This way, the event will not call itself and we prevent stackoverflow error
            
                // Your code is here
            });
        }

        void EnglishBoxItem_OnSelected(object sender, RoutedEventArgs e)
        {
            eventExecutor.Execute(() =>
            {
                // This is safe section where to process the event.
                // This way, the event will not call itself and we prevent stackoverflow error
            
                // Your code is here
            });
        }

        void ChineseBoxItem_OnSelected(object sender, RoutedEventArgs e)
        {
            eventExecutor.Execute(() =>
            {
                // This is safe section where to process the event.
                // This way, the event will not call itself and we prevent stackoverflow error
            
                // Your code is here
            });
        }
    }
}