我的应用程序中有很多ToggleSwitch
和Combobox
控件,我在应用程序启动时设置它们,它会触发与这些控件关联的所有事件。
这些事件只有在用户与控件交互时才会触发,而不是以编程方式更改值时触发。
有没有办法禁用所有事件并在之后重新激活它们?
我在其他帖子或互联网上找不到任何有效的解决方案。
答案 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
});
}
}
}