简体   繁体   English

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

[英]Handle events from DataTemplate in custom control

I am writing a WPF client and have created a custom Chat control that will be used within the client, the Chat control comprises of a ChatClient that handles joining and leaving the Chat service and displaying a list of connected Users as per the following XAML: 我正在编写一个WPF客户端,并创建了一个将在客户端中使用的自定义聊天控件,聊天控件包含一个ChatClient,用于处理加入和离开聊天服务,并按照以下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>

This is defined in a ResourceDictionary in the Chat assembly and the ChatClient is added as a control to the main application window. 这在Chat程序集的ResourceDictionary中定义,ChatClient作为控件添加到主应用程序窗口。

This is all great and when I run the application it connects to the chat server and I get a nice panel to the right of the main window with a list of connected users. 这一切都很棒,当我运行应用程序时,它连接到聊天服务器,我在主窗口右侧有一个很好的面板,其中包含已连接用户的列表。

Ok, so my question is specifically related to the following part from the XAML above: 好的,所以我的问题与上面的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>

In the above DataTemplate an item is created for each connected Person, I would like to know how I can handle the MouseDoubleClick event of the ContentControl from the ChatClient, so that the ChatClient will be responsible for creating the ChatWindow, examples would be good as still quite new to WPF. 在上面的DataTemplate中,为每个连接的Person创建了一个项目,我想知道如何从ChatClient处理ContentControl的MouseDoubleClick事件,以便ChatClient将负责创建ChatWindow,示例仍然很好对WPF来说很新鲜。

I have been reading up on Attached Behaviors but struggling to understand how these would fit in to what I am looking to achieve which is that my ChatClient class has an event handler that is fired when I double click any item added within the DataTemplate. 我一直在阅读Attached Behaviors,但很难理解它们如何适应我想要实现的目标,即我的ChatClient类有一个事件处理程序,当我双击DataTemplate中添加的任何项目时会触发该事件处理程序。

Any suggestions on how to achieve this will be greatly received. 任何有关如何实现这一目标的建议都将受到极大欢迎。

I recommend you to fire a Command on MouseDoubleClick event. 我建议你在MouseDoubleClick事件上触发一个Command

To connect a MouseDoubleClick event to a Command and pass ClientId to it, you can use somethings like this: 要将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>

Then you can simply define ClientDoubleClickCommand command in ClientChat class (like other members of it such as People ): 然后你可以简单地在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--------
    .
    .
    .

}

In this example, i assumed you have a ClientId property in your People class to keep id of each client. 在此示例中,我假设您在People类中具有ClientId属性以保留每个客户端的ID。

Now you have a People property, it is a list of clients and you used it like this: 现在你有一个People属性,它是一个客户列表,你用它像这样:

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

On the other hand if the ItemsControl DataContext be »» ChatClient class then we have access to ClientDoubleClickCommand in it and access to ClientId in People class (by ItemsSource ) in the following line inside ItemsControl block: 另一方面, 如果 ItemsControl DataContext是»» ChatClient类, 那么我们可以访问其中的ClientDoubleClickCommand ,并在ItemsControl块内的以下行中访问People类中的ClientId (通过ItemsSource ):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM