WPF MVVM itemsControl и кнопка команды не работает? - PullRequest
0 голосов
/ 15 февраля 2020

У меня проблема с моим приложением WPF MVVM. У меня есть представление (CaisseView.xaml) и его ViewModel (CaisseViewModel.cs, который используется как Datacontext для представления, вызванного с другой .cs). На мой взгляд, я использую itemsControl, чтобы иметь кнопку для каждого элемента наблюдаемой коллекции модели. Более того, на мой взгляд, у меня есть ListView. Я хочу, чтобы каждый раз, когда нажималась кнопка itemsControl, в моем Lisview появлялась новая строка. Это последнее, что это не работает! Используя debug, я ввожу в свою команду команду, добавляющую объект в мою наблюдаемую коллекцию, но приложение не актуализирует View.

В моей ViewModel я использую INotifyPropertyChanged, RelayCommand и ICommand.

Я дам тебе мой код. Можете ли вы помочь мне с моим вопросом ??? спасибо:

My View:

<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! Поэтому Datacontextof кнопки не моя viewModel, поэтому я использую staticResource ...

Я надеюсь, что что-то мне поможет :) большое спасибо.

1 Ответ

1 голос
/ 16 февраля 2020

Добро пожаловать на ТАК! Для дальнейшего использования у вас будет гораздо больше шансов получить ответы на свои вопросы, если вы отправите MCVE , в том, что вы разместили, достаточно ненужного кода, чтобы вывести большинство людей из строя.

Чтобы ответить на ваш вопрос, на самом деле с этим кодом много чего не так, но основная проблема заключается в том, что вы создаете обработчики обратного вызова типа RelayCommand, однако ваш обработчик команд (AddProductToBill) ожидает параметр объекта и, следовательно, должен иметь тип RelayCommand<object>. (Еще более странно, что одна из ваших привязок передается в CommandParameter, а другая нет).

Еще одна вещь, которую следует избегать, - это объявление модели представления в блоке ресурсов, обычно это не делается по разным причинам. (Вы уверены, что назначаете этот экземпляр как свой DataContext, а не объявляете новый?). Если вы назначаете свой DataContext где-то еще, тогда ваши элементы списка могут связываться с ним примерно так:

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