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

标签 c# mvvm prism routed-commands

我正在尝试根据 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; }
}

View 模型

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 之间的链接是通过使用:

prism:ViewModelLocator.AutoWireViewModel="True"

在我看来(这有效)。

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

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

最佳答案

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

长答案:

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

型号:

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>

关于c# - 使用 Prism 库将 ListView 项传递给命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35653879/

相关文章:

c# - 强制子类通过父类覆盖祖先的功能

c# - 在 Unity 中在 Sprite 上写文本

c# - 使用 Caliburn.Micro 将命令绑定(bind)到 ListView 内的按钮

wpf - PRISM RegionManager - TabControl 选项卡顺序

c# - 将参数从ConfirmNavigationRequest传递到Prism中的NavigationService

c# - 将耗时的进程从我的 ASP.NET 应用程序中移走

c# - 将大量 (~1000-2000) Jpeg 图像合并为一个

c# - 如何在 BarChart 中绑定(bind)列表中的值

c# - 在 MVVM 应用程序中使用 autofac

Silverlight Prism 事件聚合器不可靠