Stelios
Stelios

Reputation: 340

wpf popup inside user control, button not respond to events or commands

I have the following user control xaml

<UserControl x:Class="tgltestpopup"
         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:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <Popup  IsOpen="{Binding ElementName=tgl,Path=IsChecked}" StaysOpen="False">
        <Border Background="White">
            <StackPanel>
                <Button Click="showMsgEvent" Content="close"></Button>
                <Button Content="test me" Command="{Binding showMsgCommand,RelativeSource={RelativeSource AncestorType=UserControl}}"></Button>

            </StackPanel>
        </Border>
    </Popup>
    <ToggleButton Content="open popup" x:Name="tgl" HorizontalAlignment="Center" VerticalAlignment="Center"/>

</Grid>

this user control is used inside a datagrid Template column . How ever when i click the toggle button the popup displays but the buttons not respond to the events or commands . The buttons are highlighted when the mouse pass over them but when i click them do nothing!.even when i press the button the button state dose not change . Looks like don't recognize the button that i clicked it.

Any suggestion?

Upvotes: 2

Views: 1158

Answers (1)

Olaru Mircea
Olaru Mircea

Reputation: 2620

I got this working by using an EventTrigger and PreviewMouseDown. For some reason, MouseDown is not working and i think this is the reason the simple command fails too. Maybe the focus is changing and the button is not really clicked in fact.

But anyway, here is what I came up with:

<Window x:Class="TestPopupInDataTemplate.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:TestPopupInDataTemplate"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <DataGrid AutoGenerateColumns="False"
              ItemsSource="{Binding Source}"
              CanUserAddRows="False">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="First">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <local:TestUserControl/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

        </DataGrid.Columns>
    </DataGrid>
</Grid>

To get over it fast, i didn't add a separate view model for the Window:

public partial class MainWindow : Window
{
    public ObservableCollection<TestViewModel> Source { get; set; }
    public MainWindow()
    {
        InitializeComponent();
        Source = new ObservableCollection<TestViewModel>() { new TestViewModel() { Name = "Test Name11" } };
        this.DataContext = this;
    }
}

Here is UserControl which is set on the DataTemplate:

<UserControl x:Class="TestPopupInDataTemplate.TestUserControl"
         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" 
         xmlns:local="clr-namespace:TestPopupInDataTemplate"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="GridName">
    <ToggleButton Content="open popup" x:Name="tgl" HorizontalAlignment="Center" VerticalAlignment="Center"/>

    <Popup  IsOpen="{Binding ElementName=tgl,Path=IsChecked}" 
            StaysOpen="False"                >
        <Border Background="White">
            <StackPanel>
                <!--<Button Click="showMsgEvent" Content="close"></Button>-->
                <Button Content="{Binding Name}"
                        Margin="5"
                        Width="90"
                        Height="30"
                        FontSize="20"                            >
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="PreviewMouseDown">
                            <i:InvokeCommandAction Command="{Binding ShowMsgCommand}" 
                                                   CommandParameter="{Binding}"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>

            </StackPanel>
        </Border>
    </Popup>
</Grid>

Its view model :

public class TestViewModel
{
    public ICommand ShowMsgCommand { get; set; }

    public string Name { get; set; }
    public TestViewModel()
    {
        ShowMsgCommand = new OpenMsgCommand(this);
    }
    public void OpenMessage()
    {
        Console.WriteLine("test");
    }
}

And the command:

public class OpenMsgCommand : ICommand
{
    private TestViewModel _vm;

    public OpenMsgCommand(TestViewModel vm)
    {
        _vm = vm;
    }
    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        _vm.OpenMessage();
    }
}

Here is the result:

enter image description here

As you see, both the command and command parameter are working as expected.

You need to add a reference to System.Windows.Interactivity in order to use Interaction.Triggers.

Upvotes: 1

Related Questions