WPF MVVM itemsControl 和按钮命令不起作用?

WPF MVVM itemsControl and button command does not work?

我的 WPF MVVM 应用程序有问题。 我有一个视图 (CaisseView.xaml) 及其 ViewModel(CaisseViewModel.cs,用作自另一个 .cs 以来调用的视图的数据上下文)。 在我看来,我正在使用 itemsControl 以便为模型的可观察集合的每个元素设置一个按钮。此外,在我看来,我有一个 ListView。我希望每次单击 itemsControl 的按钮时,我的 Lisview 中都会出现一个新行。 这最后一件事是行不通的! 使用 debug 我输入我的命令,该命令将一个对象添加到我的可观察集合中,但应用程序没有实现视图。

在我的 ViewModel 中,我正在使用 INotifyPropertyChanged、RelayCommand 和 ICommand。

我给你我的代码。 你能帮我解决我的问题吗??? 谢谢:

我的看法:

<UserControl x:Class="LMarket.Views.CaisseView"
             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:local="clr-namespace:LMarket.Views"
             xmlns:localM="clr-namespace:LMarket.Models"
             xmlns:localModel="clr-namespace:LMarket.ViewModels"
             xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
             mc:Ignorable="d">
    <UserControl.Resources>
        <localModel:CaisseViewModel x:Key="CaisseViewModel"/>
        <localM:ProduitDuStock x:Key="ProduitDuStockModel"/>
    </UserControl.Resources>
    <Grid Name="MainGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Image Cursor="Hand" Source="/Resources/homepage.png" Width="32" Height="32" HorizontalAlignment="Left" Margin="15,10" Grid.Row="0">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseLeftButtonDown">
                    <i:InvokeCommandAction Command="{Binding DataContext.OnHomeCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Image>
        <Image Cursor="Hand" Source="/Resources/LogOut.png" Width="32" Height="32" HorizontalAlignment="Right" Margin="15,10" Grid.Row="0">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseLeftButtonDown">
                    <i:InvokeCommandAction Command="{Binding DataContext.BackConnectionCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Image>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>
            <Border Grid.Column="0" BorderThickness="2" BorderBrush="Azure" Margin="5,5,1,5">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="50"/>
                        <RowDefinition Height="1*" />
                        <RowDefinition Height="50" />
                        <RowDefinition Height="50"/>
                    </Grid.RowDefinitions>
                    <Grid Grid.Row="0" Background="#FFC2E0ED">
                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                            <Image Cursor="Hand" VerticalAlignment="Center"  Width="32" Height="32" Source="/Resources/files-and-folders.png"/>
                            <Image Cursor="Hand" VerticalAlignment="Center" Margin="10,0" Width="32" Height="32" Source="/Resources/cancel.png"/>
                        </StackPanel>
                    </Grid>
                    <ListView Grid.Row="1" Margin="5" SelectionMode="Single"
                              HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding Path=LstProducts, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                        <ListView.ItemTemplate>
                            <DataTemplate DataType="localM:ProduitDuStock">
                                <StackPanel Margin="2" MinWidth="244">
                                    <StackPanel.Resources>
                                        <Style TargetType="{x:Type StackPanel}">
                                           <!-- <Style.Triggers>
                                                <DataTrigger Binding="{Binding Path=Selected}" Value="True">
                                                    <Setter Property="Background" Value="LightBlue"/>
                                                </DataTrigger>
                                        </Style.Triggers> -->
                                        </Style>
                                    </StackPanel.Resources>
                                    <DockPanel >
                                        <TextBlock FontWeight="Bold" Text="Produit: " DockPanel.Dock="Left" Margin="5,0,5,0"/>
                                        <TextBlock Text="  " />
                                        <TextBlock Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="Green" FontWeight="Bold" />
                                    </DockPanel>
                                </StackPanel>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                    <DockPanel Grid.Row="2" Margin="5" Background="#FF296B88">
                        <Label Content="TOTAL" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" FontFamily="Rockwell Condensed" Foreground="#FFF2FF5A" />
                        <Label Content="$$" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" FontFamily="Rockwell Condensed" Foreground="#FFF2FF5A" />
                    </DockPanel>
                    <Grid Grid.Row="3" Background="#FFC2E0ED">
                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="2">
                            <Button Cursor="Hand" Width="80" Content="Cuenta %" Background="#FF98ADA8" BorderBrush="#FF4A6DFF" Margin="2,0">
                                <Button.Resources>
                                    <Style TargetType="{x:Type Border}">
                                        <Setter Property="CornerRadius" Value="8"/>
                                    </Style>
                                </Button.Resources>
                            </Button>
                            <Button Cursor="Hand" Width="80" Content="Producto %" Background="#FF98ADA8" BorderBrush="#FF4A6DFF" Margin="2,0">
                                <Button.Resources>
                                    <Style TargetType="{x:Type Border}">
                                        <Setter Property="CornerRadius" Value="8"/>
                                    </Style>
                                </Button.Resources>
                            </Button>
                            <Button Cursor="Hand" Width="80" Content="-1" Background="#FFDDCF00" BorderBrush="#FF4A6DFF" FontWeight="Bold" FontSize="20">
                                <Button.Resources>
                                    <Style TargetType="{x:Type Border}">
                                        <Setter Property="CornerRadius" Value="8"/>
                                    </Style>
                                </Button.Resources>
                            </Button>
                            <Button Cursor="Hand" Width="80" Content="+1" Background="#FF79C837" BorderBrush="#FF4A6DFF" FontWeight="Bold" FontSize="20" Margin="2,0">
                                <Button.Resources>
                                    <Style TargetType="{x:Type Border}">
                                        <Setter Property="CornerRadius" Value="8"/>
                                    </Style>
                                </Button.Resources>
                            </Button>
                            <Button Cursor="Hand" Width="auto" Content="  Validar para Pagar  " Command="{Binding AddNewProductCommand}" Background="#FF98ADA8" BorderBrush="#FF4A6DFF"  FontSize="19" Margin="80,0,2,0" Foreground="Black">
                                <Button.Resources>
                                    <Style TargetType="{x:Type Border}">
                                        <Setter Property="CornerRadius" Value="8"/>
                                    </Style>
                                </Button.Resources>
                            </Button>
                        </StackPanel>
                    </Grid>
                </Grid>
            </Border>
            <Border Grid.Column="1" BorderThickness="2" BorderBrush="Azure" Margin="1,5,5,5">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" MaxHeight="720"/>
                        <RowDefinition Height="1" />
                    </Grid.RowDefinitions>
                    <ScrollViewer Grid.Row="0" Background="Transparent"
                                  HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                        <ItemsControl ItemsSource="{Binding ListOfProducts}" MaxWidth="762">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Border Cursor="Hand" CornerRadius="8" Margin="4,3" BorderThickness="1.5" BorderBrush="#FFFDFF00">
                                        <Border.Background>
                                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                                <GradientStop Color="#FF6F92DC" Offset="1"/>
                                                <GradientStop Color="#FFA6DBFF" Offset="0.534"/>
                                            </LinearGradientBrush>
                                        </Border.Background>
                                        <Button BorderBrush="Transparent" Background="Transparent" Command="{Binding Source={StaticResource CaisseViewModel}, Path=AddNewProductCommand}" CommandParameter="{Binding Id}">
                                            <Button.Resources>
                                                <Style TargetType="{x:Type Border}">
                                                    <Setter Property="CornerRadius" Value="8"/>
                                                </Style>
                                            </Button.Resources>
                                            <StackPanel Orientation="Vertical" Margin="2" Width="80" Height="80">

                                                <Image Source="{Binding ProductImageUrl}" Width="40" Height="40" Margin="0,10,0,5"
                                                   HorizontalAlignment="Center"/>

                                            <Label Content="{Binding Surname}" FontWeight="Bold" HorizontalAlignment="Center" FontSize="11"/>
                                        </StackPanel>
                                        </Button>
                                    </Border>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </ScrollViewer>
                </Grid>
            </Border>
        </Grid>
    </Grid>
</UserControl>

还有我的 ViewModel:

using LMarket.Models;
using LMarket.Views;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Xml;

namespace LMarket.ViewModels
{
    class CaisseViewModel : INotifyPropertyChanged
    {
        //Event for INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged([CallerMemberName] string str = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(str));
        }

        #region Attributs
        private ObservableCollection<ProduitDuStock> listOfProducts;
        private ObservableCollection<ProduitDuStock> lstProducts;
        private ProduitDuStock selectedProduct;
        #endregion
        #region Getter/Setter
        public ObservableCollection<ProduitDuStock> ListOfProducts
        {
            get
            {
                return listOfProducts;
            }
            set
            {
                if (listOfProducts != value)
                {
                    listOfProducts = value;
                }
                NotifyPropertyChanged();
            }
        }
        public ObservableCollection<ProduitDuStock> LstProducts
        {
            get
            {
                return lstProducts;
            }
            set
            {
                if (lstProducts != value)
                {
                    lstProducts = value;
                }
                NotifyPropertyChanged();
            }
        }
        public ProduitDuStock SelectedProduct
        {
            get
            {
                return selectedProduct;
            }
            set
            {
                if (selectedProduct != value)
                {
                    selectedProduct = value;
                    NotifyPropertyChanged();
                }
            }
        }

        #endregion


        #region Constructeur
        public CaisseViewModel()
        {
            ListOfProducts = new ObservableCollection<ProduitDuStock>();
            LstProducts = new ObservableCollection<ProduitDuStock>();
            toto();
            //Lecture du fichier ou son enregistrer les données du stock (En local sur un .xml)
            try
            {
                //Ouverture du document XML
                XmlDocument xmlDoc = new XmlDocument();
                string Path = Directory.GetCurrentDirectory().ToString();
                Path = Path + "\Configuration\Stockes.xml";
                xmlDoc.Load(Path);
                //Recupérer la section des produits
                XmlNodeList nodeList = xmlDoc.DocumentElement.SelectNodes("/Stockes/Products/product");
                //Pour chaque produit dans le fichier, créer un objet ProduitDuStock et l'ajouter à l'ObservableCollection.
                foreach (XmlNode node in nodeList)
                {
                    //Creation du nouvel objet 
                    ProduitDuStock testProduit = new ProduitDuStock();
                    foreach (XmlAttribute att in node.Attributes)
                    {
                        //Récupération des parametres de l'objet.
                        switch (att.Name)
                        {
                            case "id":
                                testProduit.Id = int.Parse(att.Value);
                                break;
                            case "name":
                                testProduit.Name = att.Value;
                                break;
                            case "pays":
                                testProduit.Pays = att.Value;
                                break;
                            case "surname":
                                testProduit.Surname = att.Value;
                                break;
                            case "quantite":
                                testProduit.Quantite = int.Parse(att.Value);
                                break;
                            case "unitprice":
                                testProduit.UnitPrice = int.Parse(att.Value);
                                break;
                            case "productImageUrl":
                                testProduit.ProductImageUrl = att.Value;
                                break;
                            default:
                                break;
                        }
                    }
                    //Ajouter l'objet créé a notre ObservableCollection.
                    ListOfProducts.Add(testProduit);
                }

            }
            catch (Exception ex)
            {

            }
        }
        #endregion

        #region Command Definition
        //Event RelayCommand Definition
        private RelayCommand addProductToBill = null;
        public ICommand AddProductToBill
        {
            get
            {
                if (addProductToBill == null)
                {
                    addProductToBill = new RelayCommand(OnAddProductToBill);
                }
                return addProductToBill;
            }
        }
        private RelayCommand addNewProductCommand = null;
        public ICommand AddNewProductCommand
        {
            get
            {
                if (addNewProductCommand == null)
                {
                    addNewProductCommand = new RelayCommand(OnAddNewProductCommand);
                }
                return addNewProductCommand;
            }
        }
        #endregion

        #region Command function definition
        //Event lorsque le curseur rentre dans la zone du boutton "Stock"
        private void OnAddNewProductCommand(object obj)
        {
            toto();
        }

        private void OnAddProductToBill(object obj)
        {
            toto();
        }
        #endregion

        #region function
        public void toto()
        {
            ProduitDuStock myAddProductToBill = new ProduitDuStock();
            myAddProductToBill.Name = "trrt";
            LstProducts.Add(myAddProductToBill);
        }
        #endregion
    }
}

进入视图的重要部分是下一个:

<Button BorderBrush="Transparent" Background="Transparent" Command="{Binding Source={StaticResource CaisseViewModel}, Path=AddNewProductCommand}" CommandParameter="{Binding Id}">

请记住,此按钮已定义到 itemsControl 中!所以按钮的 Datacontext 不是我的 viewModel,所以我使用静态资源...

希望对我有所帮助 :) 非常感谢。

欢迎来到 SO!为了将来的参考,如果您 post 一个 MCVE,您将有更好的机会回答您的问题,您 post 编写的内容中有足够多的不必要代码,足以让大多数人望而却步.

为了回答您的问题,这段代码实际上有很多问题,但主要问题是您正在创建 RelayCommand 类型的回调处理程序,而您的命令处理程序 (AddProductToBill) 需要一个对象参数,因此应该是 RelayCommand<object> 类型。 (更令人困惑的是,您的绑定之一正在传递 CommandParameter,而另一个则没有)。

另一件要避免的事情是在你的资源块中声明你的视图模型,由于各种原因通常不会这样做(你确定你正在将该实例分配为你的 DataContext 而不是声明一个新的吗?) .如果你在别处分配你的 DataContext 那么你的列表元素可以像这样绑定到它:

<UserControl ...
    x:Name="_this">
    .
    .
    <!-- Inside ItemsControl.ItemTemplate -->
    <Button
        Command="{Binding ElementName=_this, Path=DataContext.MyHandler}"
        CommandParameter="{Binding}" ... />