使用 Prism 库将 ListView 项传递给命令

Passing ListView Items to Commands using Prism Library

我正在尝试执行基于列表视图项目数据的方法。除此之外,如果列表视图项的 "CanExecute" 方法 returns 为真,则应仅启用触发命令的按钮。

"MyCommand" 和 "CanExecute" 这两种方法都包含在我的 ViewModel 中。 不幸的是,我不确定如何将项目信息正确地传递给这两种方法以符合 PRISM 6 框架。

所以我的第一个方法是像下面这样:

型号

public class MyModel
{
    public string Name { get; set; }
    public string Version { get; set; }
    public int Identifier { get; set; }
}

ViewModel

public class MyViewModel : BindableBase
{

    private ObservableCollection<MyModel> _models = new ObservableCollection<MyModel>();
    public ObservableCollection<MyModel> Models
    {
        get { return _models; }
        set { SetProperty(ref _models, value); }
    }

    public DelegateCommand VerifyCommand { get; set; }


    public MyViewModel()
    {
        //Add test data
        for (int i = 0; i < 5; i++)
        {
            MyModel model = new MyModel();
            model.Name = "Random Text";
            model.Version = "Random Text";
            model.Identifier = i;

            Models.Add(model);
        }

        //Doesn't work, because I don't reference to "Models"
        //How to do that?
        VerifyCommand = new DelegateCommand(DoCommand, CanExecute).ObservesProperty<string>(() => Name).ObservesProperty<string>(() => Version);
    }

    private bool CanExecute()
    {
        //Obviously this doesn't work, because "Version" and "Name" 
        //don't belong to the selected "Models" item of the listview

        //What is the "bridge", to know which item of Models was clicked (button)
        return !String.IsNullOrWhiteSpace(Version) && !String.IsNullOrWhiteSpace(Name);
    }

    private void DoCommand()
    {
        //Do something special
    }
}

查看

<ListView ItemsSource="{Binding Models}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid Height="Auto" Margin="0,0,0,10">
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <TextBox Grid.Row="0" Tag="VERSION" Text="{Binding Version, UpdateSourceTrigger=PropertyChanged}" />
                <TextBox Grid.Row="1" Tag="NAME" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
                <Button Command="{Binding ElementName=root, Path=DataContext.VerifyCommand}" Content="Verify" Grid.Row="2">
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

View 和 ViewModel 之间的 link 使用:

prism:ViewModelLocator.AutoWireViewModel="True"

在我看来(这有效)。

所以总结一下: 它是如何工作的,PRISM 符合 1. 仅当 CanExecute 为真时启用项目按钮和 2. 执行 "DoCommand" 方法并将项目信息传递给该方法(按钮的根元素 -> 在本例中为 ListViewItem (我的模型).

如有任何帮助,我们将不胜感激。

简答:将命令放在项目的视图模型中。

长答案:

这是我在上面评论中的意思的一个例子。我已经省略了集合的可观察性,如果你真的需要一个可观察的模型集合和一个可观察的视图模型集合,请为大量无聊的双向同步代码做好准备...

型号:

internal class ItemModel
{
    public string Name { get; set; }
    public string Version { get; set; }
    public int Identifier { get; set; }
}

ViewModels(一个用于项目集合,即您的 MyViewModel,另一个用于项目):

internal class MyCollectionViewModel : BindableBase
{
    private readonly List<ItemModel> _models = new List<ItemModel>();

    public MyCollectionViewModel()
    {
        //Add test data
        for (var i = 0; i < 5; i++)
            _models.Add( new ItemModel
            {
                // to prove that CanExecute is actually evaluated...
                Name = i == 3 ? "Random Text" : string.Empty,
                Version = "Random Text",
                Identifier = i
            } );
    }

    public IReadOnlyCollection<ItemViewModel> TheCollection => _models.Select( x => new ItemViewModel( x ) ).ToList();
}

internal class ItemViewModel : BindableBase
{
    public ItemViewModel( ItemModel item )
    {
        _item = item;
        VerifyCommand = new DelegateCommand( () =>
                                             {
                                                 /* Do something */
                                             }, () => !string.IsNullOrWhiteSpace( Version ) && !string.IsNullOrWhiteSpace( Name ) );
    }

    public string Name => _item.Name;
    public string Version => _item.Version;
    public int Identifier => _item.Identifier;

    public DelegateCommand VerifyCommand
    {
        get;
    }

    private readonly ItemModel _item;
}

查看:

<ListView ItemsSource="{Binding TheCollection}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid Height="Auto" Margin="0,0,0,10">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <TextBox Grid.Column="0" Text="{Binding Version, Mode=OneWay}" />
                <TextBox Grid.Column="1" Text="{Binding Name, Mode=OneWay}" />
                <Button Grid.Column="2" Command="{Binding VerifyCommand}" Content="Verify"/>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>