处理自定义控件中DataTemplate中的事件

本文关键字:事件 DataTemplate 处理 自定义控件 | 更新日期: 2023-09-27 18:28:26

我正在编写一个WPF客户端,并创建了一个将在客户端中使用的自定义聊天控件,聊天控件由一个聊天客户端组成,该客户端处理加入和退出聊天服务,并根据以下XAML显示连接用户列表:

<Style TargetType="{x:Type chat:ChatClient}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type chat:ChatClient}">
                <Grid Margin="0,0,0,0" Background="{StaticResource ChatClientBackgroundBrush}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="135" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <Grid Grid.Row="0" Margin="0,0,0,0" Background="{StaticResource ChatClientBackgroundBrush}">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="100" />
                            <RowDefinition Height="32" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Border Grid.Column="0" Grid.Row="0" Height="100" Margin="0,0,0,0" Padding="1,1,1,0" BorderBrush="{StaticResource ChatClientAvatarBorderBrush}">
                            <Image Height="80" Width="80" Source="Cleo.Windows.Ui.Chat;component/Resources/noavatar.png" StretchDirection="Both" Stretch="Fill">
                                <Image.Clip>
                                    <EllipseGeometry Center="40,40" RadiusX="40" RadiusY="40" />
                                </Image.Clip>
                            </Image>
                        </Border>
                        <StackPanel Grid.Column="0" Grid.Row="1" Orientation="Horizontal">
                            <Ellipse Height="8" Width="8" Fill="{StaticResource ChatClientPresenceOnlineBrush}" Margin="6,-8,0,0" />
                            <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CurrentPerson.Name}" Margin="8,0" Foreground="{StaticResource ChatClientTextBrush}"
                                       FontSize="16" />
                        </StackPanel>
                    </Grid>
                    <Border Grid.Row="1" BorderThickness="0,1,0,0" BorderBrush="{StaticResource ChatClientBorderBrush}">
                        <Grid Background="{StaticResource ChatClientBackgroundBrush}">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*" MinHeight="100" />
                            </Grid.RowDefinitions>
                            <ScrollViewer x:Name="srcContacts" Grid.Row="0" Margin="0,0,0,0" VerticalScrollBarVisibility="Auto">
                                <StackPanel>
                                    <ItemsControl ItemsSource="{Binding Path=People, RelativeSource={RelativeSource AncestorType={x:Type chat:ChatClient}}}" x:Name="Contacts">
                                        <ItemsControl.ItemTemplate>
                                            <DataTemplate>
                                                <ContentControl>
                                                    <Border Style="{StaticResource IsMouseOver}">
                                                        <Grid>
                                                            <Grid.ColumnDefinitions>
                                                                <ColumnDefinition Width="40" />
                                                                <ColumnDefinition Width="*" />
                                                            </Grid.ColumnDefinitions>
                                                            <Grid.RowDefinitions>
                                                                <RowDefinition Height="*" />
                                                                <RowDefinition Height="*" />
                                                            </Grid.RowDefinitions>
                                                            <Border Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Top" Height="35" Width="35" Margin="5,0,0,0"
                                                                BorderBrush="{StaticResource ChatClientPresenceOnlineBrush}" BorderThickness="2" CornerRadius="15">
                                                                <Image Height="30" Width="30" Source="Cleo.Windows.Ui.Chat;component/Resources/noavatar.png" StretchDirection="Both" Stretch="Fill">
                                                                    <Image.Clip>
                                                                        <EllipseGeometry Center="15,15" RadiusX="15" RadiusY="15" />
                                                                    </Image.Clip>
                                                                </Image>
                                                            </Border>
                                                            <TextBlock Grid.Column="1" Grid.Row="0" Foreground="{StaticResource ChatClientTextBrush}" Padding="0" Margin="10,0,0,0" FontWeight="Bold"
                                                                   Text="{Binding Name}"></TextBlock>
                                                        </Grid>
                                                    </Border>
                                                </ContentControl>
                                            </DataTemplate>
                                        </ItemsControl.ItemTemplate>
                                    </ItemsControl>
                                </StackPanel>
                            </ScrollViewer>
                        </Grid>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这是在Chat程序集中的ResourceDictionary中定义的,ChatClient作为控件添加到主应用程序窗口中。

这一切都很好,当我运行应用程序时,它会连接到聊天服务器,我会在主窗口右侧看到一个很好的面板,上面有一个连接的用户列表。

好的,所以我的问题具体与上面XAML的以下部分有关:

<ScrollViewer x:Name="srcContacts" Grid.Row="0" Margin="0,0,0,0" VerticalScrollBarVisibility="Auto">
    <StackPanel>
        <ItemsControl ItemsSource="{Binding Path=People, RelativeSource={RelativeSource AncestorType={x:Type chat:ChatClient}}}" x:Name="Contacts">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <ContentControl>
                        <Border Style="{StaticResource IsMouseOver}">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="40" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="*" />
                                </Grid.RowDefinitions>
                                <Border Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Top" Height="35" Width="35" Margin="5,0,0,0" BorderBrush="{StaticResource ChatClientPresenceOnlineBrush}" BorderThickness="2" CornerRadius="15">
                                    <Image Height="30" Width="30" Source="Cleo.Windows.Ui.Chat;component/Resources/noavatar.png" StretchDirection="Both" Stretch="Fill">
                                        <Image.Clip>
                                            <EllipseGeometry Center="15,15" RadiusX="15" RadiusY="15" />
                                        </Image.Clip>
                                    </Image>
                                </Border>
                                <TextBlock Grid.Column="1" Grid.Row="0" Foreground="{StaticResource ChatClientTextBrush}" Padding="0" Margin="10,0,0,0" FontWeight="Bold" Text="{Binding Name}"></TextBlock>
                            </Grid>
                        </Border>
                    </ContentControl>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</ScrollViewer>

在上面的DataTemplate中,为每个连接的人创建了一个项目,我想知道如何从ChatClient处理ContentControl的MouseDoubleClick事件,这样ChatClient将负责创建ChatWindow,示例对WPF来说还是很新的。

我一直在阅读附加行为,但很难理解这些行为如何与我想要实现的目标相适应,即我的ChatClient类有一个事件处理程序,当我双击DataTemplate中添加的任何项目时,该事件处理程序就会被激发。

任何关于如何实现这一目标的建议都将大受欢迎。

处理自定义控件中DataTemplate中的事件

我建议您在MouseDoubleClick事件上激发Command

要将MouseDoubleClick事件连接到Command并将ClientId传递给它,可以使用以下方法:

<ScrollViewer x:Name="srcContacts" Grid.Row="0" Margin="0,0,0,0" VerticalScrollBarVisibility="Auto">
    <StackPanel>
        <ItemsControl ItemsSource="{Binding Path=People, RelativeSource={RelativeSource AncestorType={x:Type chat:ChatClient}}}" x:Name="Contacts">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <ContentControl>
                         <!-- ــــInputBinding For Mouse LeftDoubleClickــــ -->
                         <ContentControl.InputBindings>
                              <MouseBinding Gesture="LeftDoubleClick"
                                            Command="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl},Path=DataContext.ClientDoubleClickCommand}" 
                                            CommandParameter="{Binding ClientId}"/>
                         <ContentControl.InputBindings>
                         <!-- ــــــــــــــــــــــــــــــــــــــــ -->
                        <Border Style="{StaticResource IsMouseOver}">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="40" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="*" />
                                </Grid.RowDefinitions>
                                <Border Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Top" Height="35" Width="35" Margin="5,0,0,0" BorderBrush="{StaticResource ChatClientPresenceOnlineBrush}" BorderThickness="2" CornerRadius="15">
                                    <Image Height="30" Width="30" Source="Cleo.Windows.Ui.Chat;component/Resources/noavatar.png" StretchDirection="Both" Stretch="Fill">
                                        <Image.Clip>
                                            <EllipseGeometry Center="15,15" RadiusX="15" RadiusY="15" />
                                        </Image.Clip>
                                    </Image>
                                </Border>
                                <TextBlock Grid.Column="1" Grid.Row="0" Foreground="{StaticResource ChatClientTextBrush}" Padding="0" Margin="10,0,0,0" FontWeight="Bold" Text="{Binding Name}"></TextBlock>
                            </Grid>
                        </Border>
                    </ContentControl>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</ScrollViewer>

然后,您可以在ClientChat类中简单地定义ClientDoubleClickCommand command(就像它的其他成员,如People):

public class ChatClient: INotifyPropertyChanged
{
    //-------- Peopole property --------
    .
    .
    .
    //-------- ClientDoubleClickCommand --------
    ICommand clientDoubleClickCommand;
    public ICommand ClientDoubleClickCommand
    {
        get
        {
            return clientDoubleClickCommand ??
                (clientDoubleClickCommand = new MyCommand(DoThisOnDoubleClick, true));
        }
    }
    private void DoThisOnDoubleClick(object clientId)
    {
        // Write your target codes (on Mouse Left Double Click) here:
        throw new NotImplementedException();
    }
    //-------- OTHER PROPERTIES AND CODES OF CLASS--------
    .
    .
    .
}
// MyCommand Class: This class is a technique to implement commands easily
public class MyCommand: ICommand
{
    private readonly Action<object> _action;
    private readonly bool _canExecute;
    public MyCommand(Action<object> action, bool canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }
    public bool CanExecute(object parameter)
    {
        return _canExecute;
    }
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter)
    {
        _action(parameter);
    }
}
public class People: INotifyPropertyChanged
{
   // ClientId Property:
    .
    .
    .
   // ClientName Property:
    .
    .
    .
   //-------- OTHER PROPERTIES AND CODES OF CLASS--------
    .
    .
    .
}

在本例中,我假设您的People类中有一个ClientId属性来保存每个客户端的id。

现在您有了一个People属性,它是一个客户端列表,您这样使用它:

<ItemsControl ItemsSource="{Binding Path=People,........

另一方面,如果ItemsControl DataContext是»»ChatClient然后我们可以访问其中的ClientDoubleClickCommand,并在ItemsControl块内的以下行中访问People类中的ClientId(通过ItemsSource):

<MouseBinding Gesture="LeftDoubleClick"
              Command="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl},Path=DataContext.ClientDoubleClickCommand}" 
              CommandParameter="{Binding ClientId}"/>