简体   繁体   中英

Wpf listview where listviewitem is a custom button

I have a problem. I have a list view in my xaml:

<ListView 
        Margin="0 10 0 0"
        DockPanel.Dock="Top"
        ItemsSource="{Binding Items}"
        ScrollViewer.VerticalScrollBarVisibility="Hidden"
        ScrollViewer.HorizontalScrollBarVisibility="Disabled"
        BorderThickness="0"
        SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <local:ItemView/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

My item view looks like this (which is in UserControl tag):

<buttons:MyButton
    cal:Message.Attach="DoSomething">
    <buttons:MyButton.Visual>
        <DockPanel
            HorizontalAlignment="Left">
            <local:Image 
                DockPanel.Dock="Left"
                CountryCode="{Binding Source}"/>

            <TextBlock 
                DockPanel.Dock="Left" 
                VerticalAlignment="Center"
                Padding="15 0 0 0"
                FontFamily="{StaticResource MediumFont}"
                FontSize="16"
                Foreground="{StaticResource DarkText}"
                Text="{Binding TextValue}" />
        </DockPanel>
    </buttons:MyButton.Visual>
</buttons:MyButton>

Now the problem is that when i click on the list item, my selectedItem is not set. It always null unless I click on the very edge of the list item, then it sets the selected value, but i have to click again in the middle of the item to call the action I want.

My question is: How can I make my list view item on click (on the whole item plot) set the selected item and call the action I want?

PS I am using Caliburn Micro if this helps...

If you don't mind using code behind or a view model, you could do something like this:

<ListView.ItemTemplate>
  <DataTemplate>
     <Button BorderBrush="Transparent" Background="Transparent" Focusable="False">
        <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <i:InvokeCommandAction Command="{Binding DataContext.ClickCommand, ElementName=ListViewName}" CommandParameter="{Binding}"/>
                </i:EventTrigger>
        </i:Interaction.Triggers>
        <!-- YOUR TEMPLATE HERE -->
      <Button.Template>
  </DataTemplate>
</ListView.ItemTemplate>

This is a view/control related thing. You could handle the Click event for the Button and explicitly set the IsSelected property of the parent ListViewItem container like this:

private void OnClick(object sender, RoutedEventArgs e)
{
    var listViewItem = FindParent<ListViewItem>(sender as DependencyObject);
    if (listViewItem != null)
        listViewItem.IsSelected;
}

private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
{
    var parent = VisualTreeHelper.GetParent(dependencyObject);

    if (parent == null) return null;

    var parentT = parent as T;
    return parentT ?? FindParent<T>(parent);
}

XAML:

<ListView.ItemTemplate>
    <DataTemplate>
        <local:ItemView ButtonBase.Click="OnClick"/>
    </DataTemplate>
</ListView.ItemTemplate>

Or you could set the SelectedItem property of the ListView to the DataContext of the element:

private void OnClick(object sender, RoutedEventArgs e)
{
    FrameworkElement fe = sender as FrameworkElement;
    if (fe != null)
        listView.SelectedItem = fe.DataContext;    
}

XAML:

<ListView x:Name="listView" ... />

I know this is an old question, but what I think you were looking for is something like this

<ListView ItemsSource="{Binding ListViewItemTemplates}">
    <ListView.ItemTemplate>
         <DataTemplate>
             <StackPanel>
                 <Button x:Name="StartPage">
                     <i:Interaction.Triggers>
                         <i:EventTrigger EventName="Click">
                             <cal:Action.Target>
                                 <cal:ActionMessage MethodName="StartPage">
                                     <cal:Parameter Value="{Binding}" />
                                 </cal:ActionMessage>
                             </cal:Action.Target>
                         </i:EventTrigger>
                     </i:Interaction.Triggers>

                     <Button.Template>
                         <ControlTemplate>
                             <StackPanel Width="210" Orientation="Horizontal">
                                 <Image Source="{Binding Path=Source}"
                                        Stretch="None" />

                                 <TextBlock Text="{Binding Path=Name}" />
                             </StackPanel>
                         </ControlTemplate>
                     </Button.Template>
                 </Button>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
<ListView/>

Then you can easily bind this with the following

private ObservableCollection<ListViewItemTemplate> listViewItemTemplates;

public ObservableCollection<ListViewItemTemplate> ListViewItemTemplates
{
    get => listViewItemTemplates;
    set
    {
        listViewItemTemplates = value;
        this.OnPropertyChanged("ListViewItemTemplates");
    }
}

Where ListviewItemTemplate is a class consisting of two strings Name and Source

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