WPF:如何为自定义用户控件创建事件?

时间:2011-03-29 13:28:12

标签: wpf event-handling wpf-controls

我创建了一个由UserControl组成的ItemsCollection。此集合中的每个项目都包含ListBox

我的应用程序由Window表示,其中包含此UserControl。我希望能够管理与ListBox内的项目相关的事件。我怎样才能做到这一点? (我不确定这是否相关,但UserControl与应用程序不同。

以下是UserControl的代码:

<UserControl 
    x:Class="UserControls.CalendarMonthViewControl.CalendarMonthView"
    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" 
    mc:Ignorable="d" 
    d:DesignWidth="580" 
    d:DesignHeight="300" 
    xmlns:calendarMonthViewControl="clr-namespace:UserControls.CalendarMonthViewControl" 
    Name="CalendarMonthViewControl">
  <Grid>
    <ItemsControl 
        ItemsSource="{Binding ElementName=CalendarMonthViewControl, Path=Days}">
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <UniformGrid Rows="6" Columns="7" />
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
      <ItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type calendarMonthViewControl:Day}">
          <Border>
            <Grid>
              <ListBox ItemsSource="{Binding Path=CalendarDayItems}" />
            </Grid>
          </Border>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>
  </Grid>
</UserControl>

3 个答案:

答案 0 :(得分:2)

@vlad走在正确的轨道上。

这里有几个选择。它们都涉及处理路由事件。

要处理路由事件,请使用拥有类的名称,后跟事件名称。

第一个选项是简单地处理ListBox类上的选择更改事件(或其他一些Window事件):

<Window ...
        ListBox.SelectionChanged="OnChildListboxSelectionChanged">
   ...
</Window>

第二个选项(更典型的方法)是处理UserControl内部的ListBox事件,然后以某种方式聚合它们并在该级别触发事件。然后由Window处理此事件。此事件可以是路由事件或标准.NET事件。

<UserControl ...
             ListBox.SelectionChanged="OnChildListBoxSelectionChanged">
   ...
</UserControl>

用户控制的代码:

public event EventHandler<MyArgTypeEventArgs> ListBoxUpdated;

private void OnChildListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
   // aggregate data and info
   MyArgTypeEventArgs handler = ListBoxUpdated;
   if (handler != null)
      handler.Invoke(this, GenerateArgs());
}

Window处理此事件:

<Window ...
        ListBoxUpdated="OnListBoxUpdated">
   ...
</Window>

这应该给你一些开始。

答案 1 :(得分:1)

我自己并没有太多使用它们,但我认为RoutedEvents可以解决你的问题。事件从您的ListBox冒出来,再到Window(或树中较低的另一个元素),您可以在这里处理它们。

编辑:从链接引用:要使用XAML为事件添加处理程序,请将事件名称声明为作为事件侦听器的元素的属性。该属性的值是您实现的处理程序方法的名称,该方法必须存在于代码隐藏文件的部分类中。

因为UserControl继承自UIElement,我猜这样的东西会起作用(未经测试的atm):

<UserControl
    x:Class="UserControls.CalendarMonthViewControl.CalendarMonthView"
    [...]
    ListBox.NameOfEvent="EventHandlerName">

答案 2 :(得分:0)

我不认为你正在尝试做的是正确的方法,因为它会在你的视图之间产生不必要的依赖,并且意味着你的UserControl没有被正确封装。

在我看来,好的解决方案是处理UserControl的viewmodel中的事件,并根据需要在Window的viewmodel之间建立关系,以便视图本身是独立的。