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

4

我正在尝试根据listview项数据执行方法。除此之外,触发命令的按钮应该只在listview项的“CanExecute”方法返回true时启用。

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

所以我的第一个尝试是像以下方式:

模型

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

视图模型

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>

视图和视图模型之间的链接是通过以下方式完成的:

prism:ViewModelLocator.AutoWireViewModel="True"

在我的观点中(这个有效)。

因此,总结一下: PRISM如何符合要求,以便1.仅在CanExecute为true时启用项目按钮,并2.执行“DoCommand”方法并将项目信息传递给该按钮的根元素 -> 在这种情况下是ListViewItem(MyModel)。

任何帮助都将不胜感激。


2
你应该为你的模型创建视图模型 - 然后它们才能执行命令。也就是说,视图有一个视图模型,而该视图模型公开了一个“ModelViewModel”的列表。顺便说一句 - Models 属性可能不需要 setter,除非你计划从外部(通过数据绑定)设置它... - Haukinger
您是选择一个要验证的项目还是可以从列表中选择多个项目? - Tseng
1个回答

6

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

详细回答:

这里是我在上面评论中所说的例子。我省略了集合的可观察性,如果你真的需要一个可观察的模型集合和一个可观察的视图模型集合,那么请准备大量枯燥的双向同步代码...

模型:

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

视图模型(一个用于项集合,即您的 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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接