Wpf TabControl Interaction.Trigger fires mores than once

387 views Asked by At

I have an unexpected behaviour with a Wpf-Tabcontrol and Dataemplate with Interaction.Trgiggers.

First I define a "ViewModel". It's quite simple:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;

namespace WpfApplication3 {
    public class Vm:  INotifyPropertyChanged {


        public Vm() {
            this.CmdClick = new RelayCommand( p => this.ExecuteClick(), p => this.CanExecuteClick() ); 
        }


        private string myName;

        public string MyName {
            get { return myName; }
            set {
                if( myName != value ) {
                    myName = value;
                    if( this.PropertyChanged != null ) {
                        this.PropertyChanged( this, new PropertyChangedEventArgs( "MyName" ) );
                    }
                }
            }
        } 


        private RelayCommand cmdClick;
        public RelayCommand CmdClick {
            get { return cmdClick; }
            set { cmdClick = value; }
        }


        #region Command
        private bool CanExecuteClick() {
            return true;
        }

        public void ExecuteClick() {
            MessageBox.Show( "MyName is " + MyName );
        }
        #endregion


        public event PropertyChangedEventHandler  PropertyChanged;
    }
}

Next, I define a Datatemplate:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:l="clr-namespace:WpfApplication3"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
                    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <DataTemplate  DataType="{x:Type l:Vm}" x:Key="Vm">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBox Text="{Binding Path=MyName}" Grid.Row="0"/>
            <i:Interaction.Triggers>
                <ei:KeyTrigger Key="F5" ActiveOnFocus="True" FiredOn="KeyUp"  >
                    <i:InvokeCommandAction Command="{Binding CmdClick}" />
                </ei:KeyTrigger>
            </i:Interaction.Triggers>
        </Grid>
    </DataTemplate>
</ResourceDictionary>

I use the datatemplate on the mainform inside a TabControl:

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:WpfApplication3"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <TabControl>
        <TabItem Header="Tab1">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <ContentControl ContentTemplate="{StaticResource Vm}"  x:Name="vm11" Content="{Binding}" Grid.Row="0"/>
            </Grid>
        </TabItem>
        <TabItem Header="Tab2">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <ContentControl ContentTemplate="{StaticResource Vm}"  x:Name="vm21" Content="{Binding}" Grid.Row="0"/>
                <ContentControl ContentTemplate="{StaticResource Vm}"  x:Name="vm22" Content="{Binding}" Grid.Row="1"/> 
            </Grid>
        </TabItem>
    </TabControl>
</Window>

The code behind is simple:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication3 {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
            this.vm11.Content = vm1;

            this.vm21.Content = vm2;
            this.vm22.Content = vm3;
            this.vm1.MyName = "Name1";
            this.vm2.MyName = "Name2";
            this.vm3.MyName = "Name3";

        }

        Vm vm1 = new Vm();
        Vm vm2 = new Vm();
        Vm vm3 = new Vm();
    }    
}

When i run the program, I chlick in the first TextBox, press F5 and the MessageBox posup. Ok. I switch the tabpage, click inside the second TextBox, press F5 and the MessageBox appears again. OK. I switch back to the firsz tabpage, press F5 and the MessageBox appears twice. Uuuh. Whatss wrong. I switch back to the second tabpage,the messagebox appears twice again. After switching to the first tabpage, the messagebox is displayed treetimes now. And so on.

It is like, the KeyUp-Event is assigned internaly, when the datatemplate is displayed again, without dereferencing it. But ehat can I do ?

1

There are 1 answers

3
Taher Elhossin On

I think you need to change this property from

private RelayCommand cmdClick;
    public RelayCommand CmdClick {
        get { return cmdClick; }
        set { cmdClick = value; }

To

private RelayCommand cmdClick;
    public RelayCommand CmdClick {
        get { return cmdClick; }
        set { if(cmdClick == null)cmdClick = value;  }