wpf - WPF MVVM itemsControl 和 button 命令不起作用?
问题描述
我的 WPF MVVM 应用程序有问题。我有一个视图 (CaisseView.xaml) 和它的 ViewModel (CaisseViewModel.cs,它用作自另一个 .cs 以来调用的视图的 Datacontext)。在我看来,我正在使用 itemsControl 以便为模型的 observablecollection 的每个元素设置一个按钮。此外,在我看来,我有一个 ListView。我希望每次单击 itemsControl 的按钮时,我的 Lisview 中都会出现一个新行。最后一件事是它不起作用!使用调试我输入我的命令,该命令将一个对象添加到我的可观察集合中,但应用程序没有实现视图。
在我的 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>
我的视图模型:
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,这就是我使用staticResource的原因......
我希望对我有帮助:) 非常感谢。
解决方案
欢迎来到 SO!为了将来参考,如果您发布MCVE ,您将有更好的机会回答您的问题,您发布的内容中有足够多的不必要的代码让大多数人望而却步。
要回答您的问题,此代码实际上有很多问题,但主要问题是您正在创建 type 的回调处理程序RelayCommand
,但您的命令处理程序 (AddProductToBill) 需要一个对象参数,因此应该是 type RelayCommand<object>
。(更令人困惑的是,您的一个绑定是传入 CommandParameter,而另一个不是)。
要避免的另一件事是在资源块中声明您的视图模型,这通常由于多种原因而不会这样做(您确定将该实例分配为您的 DataContext 而不是声明一个新实例吗?)。如果您将 DataContext 分配到其他地方,那么您的列表元素可以通过以下方式绑定到它:
<UserControl ...
x:Name="_this">
.
.
<!-- Inside ItemsControl.ItemTemplate -->
<Button
Command="{Binding ElementName=_this, Path=DataContext.MyHandler}"
CommandParameter="{Binding}" ... />
推荐阅读
- php - 此路由不支持 PUT 方法。支持的方法:GET、HEAD、POST。当我使用@method('PUT')
- swift - UIImage 在 .launchimage UIImage 命令上返回 nil
- integer - 整数溢出包装和计算
- c# - 切换到开发模式
- flutter - 当我在颤振中应用计算按钮时,如何返回当前下拉列表的结果?
- c - 使用 fscanf 扫描文件后结果不正确
- react-native - React native:如果功能组件未默认导出,如何导入
- java - 如何在pdfbox中添加卢比符号
- javascript - 转换猫鼬对象时toObject不是函数错误
- javascript - 如何遍历对象数组以查找用户的 id?