NoesisGUI中的事件
NoesisGUI是一个事件驱动的框架,其中所有控件都公开了您可以订阅的一系列事件。您可以订阅这些事件,这意味着它们发生时将通知您的应用程序,您可以对此做出反应。
事件的类型很多,但是其中一些最常用的事件是用来响应用户的交互的。在大多数控件上,您会发现诸如KeyDown,KeyUp,MouseDown,MouseUp,TouchDown,TouchUp之类的事件。例如,在UIElement文档的事件部分中,您可以找到该类公开的所有事件的列表。其余课程相同。
注意
订阅
可以使用两种不同的方式来订阅NoesisGUI中的事件:有和没有code-behind。使用命令的第三种选择是将视图与模型完全分离。
直接订阅
预订事件的最简单方法是使用委托直接向事件添加回调。使用FindName可以访问该对象,因此您需要使用x:Name关键字设置所需实例的名称。例如:
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button x:Name="button" Width="100" VerticalAlignment="Center" Content="Click me"/>
</Grid>
C ++
Ptr<Grid> root = Noesis::GUI::LoadXaml<Grid>("Grid.xaml");
Button* button = root->FindName<Button>("button");
button->Click() += [](BaseComponent* sender, const RoutedEventArgs& args)
{
printf("Button was clicked");
};
C#
Grid root = (Grid)Noesis.GUI.LoadXaml("Grid.xaml");
Button button = (Button)root.FindName("button");
button.Click += (object sender, RoutedEventArgs args) =>
{
System.Console.WriteLine("Button was clicked");
};
后台代码订阅
直接预订的替代方法是使用代码隐藏类,并使用方法名称在XAML中连接事件。这些方法名称需要使用正确的事件签名在代码隐藏类中实现。例如:
<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
VerticalAlignment="Center"
x:Class="MyGrid">
<Button Width="100" Content="Click me" Click="OnButton1Click"/>
<Button Width="100" Content="Click me" Click="OnButton2Click"/>
</StackPanel>
注意
阅读扩展Noesis教程以了解有关实现代码隐藏类的更多信息
当加载XAML时,FrameworkElement公开虚拟函数ConnectEvent,该虚拟函数为每个挂钩事件调用。您需要相应地覆盖该功能。在C ++中,提供了宏NS_CONNECT_EVENT作为帮助程序,以轻松实现ConnectEvent。您必须为每个要连接的事件使用if。
C ++
class MyGrid: public Grid
{
public:
MyGrid()
{
InitializeComponent();
}
private:
void InitializeComponent()
{
Noesis::GUI::LoadComponent(this, "Grid.xaml");
}
bool ConnectEvent(BaseComponent* source, const char* event, const char* handler) override
{
NS_CONNECT_EVENT(Button, Click, OnButton1Click);
NS_CONNECT_EVENT(Button, Click, OnButton2Click);
return false;
}
void OnButton1Click(BaseComponent* sender, const RoutedEventArgs& args)
{
printf("Button1 was clicked");
}
void OnButton2Click(BaseComponent* sender, const RoutedEventArgs& args)
{
printf("Button2 was clicked");
}
NS_IMPLEMENT_INLINE_REFLECTION(MyGrid, Grid)
{
NsMeta<TypeId>("MyGrid");
}
};
C#
public class MyGrid: Grid
{
public MyGrid()
{
InitializeComponent();
}
private void InitializeComponent()
{
Noesis.GUI.LoadComponent(this, "Grid.xaml");
}
protected override bool ConnectEvent(object source, string eventName, string handlerName)
{
if (eventName == "Click" && handlerName == "OnButton1Click")
{
((Button)source).Click += this.OnButton1Click;
return true;
}
if (eventName == "Click" && handlerName == "OnButton2Click")
{
((Button)source).Click += this.OnButton2Click;
return true;
}
return false;
}
private void OnButton1Click(object sender, RoutedEventArgs args)
{
System.Console.WriteLine("Button1 was clicked");
}
private void OnButton2Click(object sender, RoutedEventArgs args)
{
System.Console.WriteLine("Button2 was clicked");
}
}
请注意,有时使用FindName不是有效的选项,而使用代码隐藏成员函数是连接事件的唯一方法。例如,当使用DataTemplate时,无法使用FindName访问可视树中的命名元素,因为为每个项目复制了数据模板。
<Grid x:Class="MyGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.Resources>
<DataTemplate x:Key="BookItemTemplate">
<StackPanel Orientation="Horizontal">
<Button Content="+" Click="OnButtonClick" />
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ListBox ItemsSource="{Binding Books}" ItemTemplate="{StaticResource BookItemTemplate}"/>
</Grid>
加载和初始化事件
在Noesis中,控件同时具有Initialized事件和Loaded事件。了解这些事件何时发生对于正确初始化任何控件类非常重要。这是这些事件如何工作的一些背景。
初始化事件
在初始化时说只是一个元素被创建,其性质已全部设置,并因此这通常他们的父母之前触发对孩子。因此,当在某个元素上引发Initialized时,可能会初始化其整个子树,但不会初始化其父树。在初始化加载的子树的XAML当事件通常被解雇。此事件对应于IsInitialized属性。
不应在类的构造函数中包含代码,而应始终使用Initialized事件。
C ++
class MainWindow final: public Noesis::UserControl
{
public:
MainWindow()
{
Initialized() += MakeDelegate(this, &MainWindow::OnInitialized);
InitializeComponent();
}
private:
void MainWindow::InitializeComponent()
{
GUI::LoadComponent(this, "MainWindow.xaml");
}
void MainWindow::OnInitialized(BaseComponent*, const EventArgs&)
{
SetDataContext(MakePtr<ViewModel>());
}
}
C#
public partial class MainWindow : UserControl
{
public MainWindow()
{
this.Initialized += OnInitialized;
this.InitializeComponent();
}
private void InitializeComponent()
{
Noesis.GUI.LoadComponent(this, "MainWindow.xaml");
}
private void OnInitialized(object sender, EventArgs args)
{
this.DataContext = new ViewModel();
}
}
载入事件
有时,初始化事件还不够。例如,您可能想知道一个元素的ActualWidth,但是当激发Initialized时,尚未计算ActualWidth值。或者,您可能想查看数据绑定属性的值,但是该值也尚未计算。
为了解决这个问题,Loaded事件表明不仅构建和初始化了元素,而且还在其上运行布局,绑定了数据,将其连接到View并处于呈现的边缘。到达该点时,将从树的根开始广播Loaded事件。此事件对应于IsLoaded属性。
与Loaded事件对称,当从已加载元素的元素树中删除元素时,发生Unloaded事件。
注意
如果不确定使用哪个事件,请使用Loaded事件。通常是正确的选择。
网友评论