简体   繁体   中英

Wpf DataTemplate Event Handlers

I have extended ListView class and created two DataTemplate for it in the separate Resource file. My question is how I can add event handlers for the Checkbox (and other items) in the DataTemplate ?

MyListView.cs

using System.Windows;
using System.Windows.Controls;

namespace WpfCustomControlLibrary1
{
    public class MyListView : ListView
    {
        public enum ListMode
        {
            List, ListCheck
        }

        public static readonly DependencyProperty ModeProperty = DependencyProperty.Register
        (
            "Mode",
            typeof(ListMode),
            typeof(MyListView),
            new PropertyMetadata(ListMode.List)
        );

        public ListMode Mode
        {
            get { return (ListMode)GetValue(ModeProperty); }
            set { SetValue(ModeProperty, value); }
        }
    }
}

MyListViewItem.cs

using System.Windows;
using System.Windows.Controls;

namespace WpfCustomControlLibrary1
{
    public class MyListViewItem:Control
    {
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register
        (
            "Text",
            typeof(string),
            typeof(MyListViewItem),
            new UIPropertyMetadata(string.Empty)
        );

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register
        (
            "IsChecked",
            typeof(bool),
            typeof(MyListViewItem),
            new UIPropertyMetadata(false)
        );

        public bool IsChecked
        {
            get { return (bool)GetValue(IsCheckedProperty); }
            set { SetValue(IsCheckedProperty, value); }
        }
    }
}

ResourceDictionary.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfCustomControlLibrary1">

    <DataTemplate x:Key="ItemTemplate_List">
        <TextBlock Text="{Binding Text}" HorizontalAlignment="Left"/>
    </DataTemplate>

    <DataTemplate x:Key="ItemTemplate_ListCheck">
        <Grid>
            <CheckBox IsChecked="{Binding IsChecked}"/>
            <TextBlock Text="{Binding Text}" Margin="20,0,0,0" HorizontalAlignment="Left"/>
        </Grid>
    </DataTemplate>

    <Style TargetType="{x:Type local:MyListView}">
        <Style.Triggers>

            <Trigger Property="Mode" Value="List">
                <Setter Property="ItemTemplate" Value="{StaticResource ItemTemplate_List}"/>
            </Trigger>

            <Trigger Property="Mode" Value="ListCheck">
                <Setter Property="ItemTemplate" Value="{StaticResource ItemTemplate_ListCheck}"/>
            </Trigger>

        </Style.Triggers>
    </Style>

</ResourceDictionary>

Your question refers to Event handlers and the use of them in Resource files. Access to the code-behind cannot be expressed directly in XAML stored in resource files.

While you are able to do the following in the XAML of a UserControl,

    <CheckBox Click="CheckBox_OnClick"/>

this is simply not possible when the style is detached in a separate resource directory.

This is where the ICommand interface becomes useful to trigger, usually, on the ViewModel but can also be used to trigger code-behind. The syntax then becomes (if you are looking to trigger code-behind):-

   <CheckBox Command="{Binding CheckBoxClickedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType='MyListView'}}"/>

This would allow you to trigger code in your MyListView class if you:-

  1. Add a property called CheckBoxClickedCommand to your MyListView class
  2. Add the supporting interface for ICommand on that property of that class

It is common to use the RelayCommand implementation so you can supply Lambda Expressions to simplify the implementation. A quick search on RelayCommand will give you some guidance.

This all sounds good until you find out that only certain controls (eg Button , Checkbox , RadioButton ) implement the Command pattern as standard.

Luckily since Blend 3 we now have more scope to use the ICommand pattern using Behaviours, again something you might want to research.

  <CheckBox Command="{Binding CheckBoxClickedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseEnter">
                <i:InvokeCommandAction Command="{Binding CheckBoxMouseEnterCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Checkbox>

Here other events such as MouseEnter can be used to fire off an ICommand call. This also means other controls that did not support the Command= property can also call the code-behind.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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