XAML UserControl的ItemsControl将ICommand传递回ViewModel MVVM

5sxhfpxr  于 2023-09-28  发布在  其他
关注(0)|答案(1)|浏览(115)

我有一个绑定到“ItemsView”视图的“ItemsViewModel”ViewModel。在ViewModel中,我有完整的属性List 'ItemsList',它绑定到ItemsControls ItemsSource。然后将DataTemplate设置为名为“ItemControl”的UserControl。
这工作得很好,在UserControl中,我可以绑定到模型中的公共属性,我假设根据我所读到的内容,这是最合适的方法,但我不确定如何将按钮命令传播回ViewModel。
在下面的代码中,我使用的方法是使用'Finderstor',但这感觉不对。
{Binding AddItemCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl, AncestorLevel=2}}">
我也读过关于将整个UserControl绑定到它自己的ViewModel的不同意见。例如,如果UserControl现在需要有10个按钮,这使得它变得复杂,而这个论点是说UserControl应该简单,但为什么它们必须简单呢?我对UserControls的使用是,我想创建一个“视图”,我想重复10次,也许100次,也许500次,如果这个视图很复杂,有多个按钮和控件类型,它是否保证它自己的ViewModel?
任何帮助或信息来源,这将是非常感谢!
视图模型:

public class ItemsViewModel : ViewModelBase
    {
        public ICommand AddItemCommand { get; }

        public ItemsViewModel()
        {
            AddItemCommand = new CommandBase(AddItem);
        }

        private void AddItem(object obj)
        {
             *Code to run on button press*
        }

        private List<ItemList> itemsList;
        public List<ItemList> ItemsList
        {
            get
            {
                return itemsList;
            }
            set
            {
                itemsList = value;
                OnPropertyChanged(nameof(ItemsList));
            }
        }
    }

产品型号:

public class ItemList
    {
        public string Name { get; set; }
        public double Amount { get; set; }
    }

    public class ItemLists
    {
        public List<ItemList> itemLists { get; set; }

        public double totalAmount
        {
            get
            {
                double totalAmount = 0;

                foreach (var item in itemLists)
                {
                    totalAmount = totalAmount + item.Amount;
                }

                return totalAmount;
            }
        }
    }

检视:

<ItemsControl ItemsSource="{Binding ItemsList}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <usercontrol:ItemControl/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

用户控制:

<Button Command="{Binding AddItemCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl, AncestorLevel=2}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <TextBlock Grid.Row="0" Text={Binding Name}/>
        <TextBlock Grid.Row="1" Text={Binding Amount}/>
    </Grid>
</Button>
arknldoa

arknldoa1#

您的问题涉及MVVM(模型-视图-视图模型)架构的一个重要方面:当视图模型需要响应用户交互时,如何处理视图中的用户交互。您有几个选项可以在不使用RelativeSource方法的情况下实现这一点:
UserControl-ViewModel配对:一种常见的方法是让每个UserControl与自己的ViewModel配对。在您的示例中,您有一个ItemControl UserControl,它表示ItemsList中的一个项。此UserControl可以有自己的ViewModel,这允许它处理自己的交互。
为ItemControl创建ViewModel(例如,ItemViewModel)。在此ViewModel中,定义AddItemCommand和该特定项所需的其他属性。将ItemControl的DataContext设置为ItemViewModel的示例。直接在ItemControl中将Button的Command绑定到AddItemCommand。这种方法允许每个项都有自己的ViewModel,如果项具有复杂的交互和数据需求,这种方法尤其有用。
传递命令:如果不希望为每个ItemControl创建单独的ViewModel,则可以将AddItemCommand从父ItemsViewModel传递到ItemsList中的每个ItemControl。您可以通过将ItemControl中的AddItemCommand绑定到一个属性来实现这一点,该属性保存对来自父ViewModel的命令的引用。
在ItemsViewModel中,可以循环访问ItemsList并为列表中的每个项设置此属性。然后,在ItemControl中,可以绑定到此属性。
这种方法允许您为每个项重用相同的ItemControl及其ViewModel,同时仍在父ViewModel中处理命令。
以下是选项2的示例:
在ItemsViewModel中,创建一个属性来保存AddItemCommand:

public ICommand AddItemCommand { get; }

在ItemsViewModel构造函数中,初始化AddItemCommand:

AddItemCommand = new CommandBase(AddItem);

在ItemsViewModel中,填充ItemsList时,为每个项设置AddItemCommand属性:

foreach (var item in ItemsList)
{
    item.AddItemCommand = AddItemCommand;
}

在ItemControl中,将Button的Command绑定到AddItemCommand属性:
(XML)

<Button Command="{Binding AddItemCommand}">
    <!-- Content of the button -->
</Button>

在ItemList类中,添加一个属性来保存命令:

public ICommand AddItemCommand { get; set; }

这样,每个ItemControl都将使用父ItemsViewModel中的相同AddItemCommand,并且您不需要依赖RelativeSource来查找命令。

相关问题