WPF确定用户在ItemsControl中单击的DataTemplate对象

时间:2014-04-17 18:28:16

标签: c# wpf mvvm datatemplate

假设在WPF中实现了一个简单的MVVM应用程序:

有一个ItemsControl的视图使用DataTemplate来解析集合中各种ViewModel的视图。

我想知道的是,如何添加功能以允许我点击ItemsControl中的给定ViewModel以在容器ViewModel中返回该元素?

也就是说,对于给定的示例,我可能希望能够点击我的WrapPanel,然后从我的BarnYardViewModel中返回ItemSource标记中的特定ViewModel。 (很像在ComboBox中绑定所选项目)

<UserControl x:Class="AGI_ServiceTool.View.DataMonitorView"
             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:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:vm="clr-namespace:MyProject.ViewModel">
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type vm:MooCowViewModel}">
            <StackPanel>
                <Image Source="/View/Images/MooCow.png"/>
                <label content="This is a Moo Cow"/>
            </StackPanel>
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:ChickenViewModel}">
            <StackPanel>
                <Image Source="/View/Images/Chicken.png"/>
                <label content="This is a Chicken"/>
            </StackPanel>
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:HorseViewModel}">
            <StackPanel>
                <Image Source="/View/Images/SarahJessicaParker.png"/>
                <label content="This is a Horse"/>
            </StackPanel>
        </DataTemplate>
    </UserControl.Resources>
    <Grid>
        <ItemsControl ItemsSource="{Binding MyAnimals}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel Orientation="Horizontal" ScrollViewer.CanContentScroll="True" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>
</UserControl>

一些基本的ViewModel:

namespace MyProject.ViewModel
{
    class AbstractViewModel : INotifyPropertyChanged { ... }
    class MooCowViewModel   : AbstractViewModel {}
    class ChickenViewModel  : AbstractViewModel {}
    class HorseViewModel    : AbstractViewModel {}

    class BarnYardViewModel : AbstractViewModel 
    {
        public BarnYardViewModel()
        {
            _myAnimals.add(new MooCowViewModel());
            _myAnimals.add(new ChickenViewModel());
            _myAnimals.add(new HorseViewModel());
        }

        private ObservableCollection<AbstractViewModel> _myAnimals = new ObservableCollection<AbstractViewModel>();

        public ICollectionView MyAnimals{
            get { return System.Windows.Data.CollectionViewSource.GetDefaultView(_myAnimals); }
        }
    }
}

2 个答案:

答案 0 :(得分:2)

我会使用常规按钮设置为无UI,并使用ViewModel

CommandParameter传递给它

例如,

<ControlTemplate x:Key="ContentOnlyTemplate" TargetType="{x:Type Button}">
    <ContentPresenter />
</ControlTemplate>

... 

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Button Command="{Binding ElementName=MyItemsControl, Path=DataContext.MyClickCommand}"
                CommandParameter="{Binding }"
                Template="{StaticResource ContentOnlyTemplate}"
                Content="{Binding }" />
    </ItemsPanelTemplate>
</ItemsControl.ItemTemplate>

这将导致ItemsControl中的每个项目都使用Button进行渲染,Button将执行您指定的任何命令,并将当前ViewModel作为CommandParameter传递。

在这种情况下,我已指定应覆盖Button.Template以使用没有用户界面的ContentPresenter,所以基本上它将是您DataTemplate的每一个动物是。

如果您有兴趣,还可以在此相关WPF问题上发布其他一些解决方案:What is the best way to simulate a Click, with MouseUp & MouseDown events or otherwise?

答案 1 :(得分:1)

StackPanel这个原因的任何原因你还想知道它是Clicked吗?

我建议您将其更改为Button并更改Template,然后将Command属性连接到ViewModel中的属性,然后说CommandParamter 1}}作为Type