我试图创建WPF应用程序以下MVVM模式everithing是好的,直到我开始绑定命令更改数据。我不明白为什么后,命令执行信息在我的列表框不更新。
下面是我的ViewModel:
class FirstVM : ObservableObject
{
private ObservableCollection<DetailScheme> _detailsScheme;
private string _text;
private ObservableCollection<Material> _materials;
private ObservableCollection<Detail> _detail;
public string Text
{
get { return _text; }
set
{
_text = value;
OnPropertyChanged();
}
}
public ObservableCollection<DetailScheme> DetailScheme
{
get { return _detailsScheme; }
}
public ObservableCollection<Material> Materials
{
get { return _materials; }
set {
_materials = value;
OnPropertyChanged();
}
}
public ObservableCollection<Detail> Details
{
get { return _detail; }
set {
_detail = value;
OnPropertyChanged();
}
}
public RelayCommand ProduceCommand { get; set; }
public FirstVM ()
{
_detailsScheme = GetDetailsScheme("D:/ DetailsScheme.json");
_materials = GetMaterials("D:/ Materials.json");
_detail = GetDetails("D:/ Details.json");
ProduceCommand = new RelayCommand(o =>
{
//this method return new ObservableCollection
Materials = GetMaterialsAfterNormalBatch(Materials, (o as DetailScheme).Materials);
Text = Materials[0].ToString();
});
}
字符串
材料类别:
class Material : ObservableObject
{
private string _name;
private int _amount;
public int Amount {
get { return _amount; }
set {
_amount = value;
OnPropertyChanged();
}
}
public string Name {
get { return _name; }
set { _name = value; }
}
public Material(string name, int amount)
{
_name = name;
_amount = amount;
}
public static ObservableCollection<Material> GetMaterials(string path)
{
ObservableCollection<Material> materials;
using (StreamReader sr = new StreamReader(path))
{
materials = JsonConvert.DeserializeObject<ObservableCollection<Material>>(sr.ReadToEnd());
}
return materials;
}
public static ObservableCollection <Material> GetMaterialsAfterNormalBatch(ObservableCollection<Material> allMaterials, ObservableCollection<Material> requiredMaterials)
{
for (int i = 0; i < allMaterials.Count; i++)
for (int j = 0; j < requiredMaterials.Count; j++)
if (allMaterials[i].Name == requiredMaterials[j].Name)
allMaterials[i].Amount -= requiredMaterials[j].Amount;
return allMaterials;
}
public override string ToString()
{
return Name+$" : {Amount}";
}
}
型
和视图:
<UserControl x:Class="Storage_Manager.MVVM.View.Task_1"
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:local="clr-namespace:Storage_Manager.MVVM.View"
xmlns:VM="clr-namespace:Storage_Manager.MVVM.ViewModel"
xmlns:View="clr-namespace:Storage_Manager.MVVM.View"
mc:Ignorable="d"
d:DesignHeight="515" d:DesignWidth="700">
<UserControl.DataContext>
<VM:FirstVM/>
</UserControl.DataContext>
<Grid>
<ComboBox x:Name="BoxOfDetails"
Height="50"
Width="250"
SelectedIndex="0"
Margin="10,10,440,455"
ItemsSource="{Binding DetailScheme}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" FontSize="18" />
<TextBlock Text="{Binding }" FontSize="9" Margin="0,7,0,0"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Content ="Produce"
Width="200"
Margin="60,460,440,10"
Command="{Binding ProduceCommand}"
CommandParameter="{Binding ElementName=BoxOfDetails, Path=SelectedItem}"/>
<ListBox ItemsSource="{Binding Materials}"
Background="Transparent"
Foreground="white"
BorderThickness="0"
IsHitTestVisible="False"/>
<TextBlock Foreground="DarkGray"
Text="{Binding Text}"/>
</Grid>
</UserControl>
型
我添加了TextBlock来查看单击按钮后信息是否更新,是的,每次单击后TextBlock数据都会更改,但ListBox保持不变。Material类实现了INotifyPropertyChanged。
2条答案
按热度按时间syqv5f0l1#
我认为问题在于你没有直接绑定到Material项的属性,而是让ToString()来完成这项工作,这是直接显示数据,但缺乏更改通知。一个只使用XAML的解决方案,保持C#代码不变,将是:
字符串
你也可以添加一个“DisplayText”字符串属性到Material类,让它像ToString现在一样返回Name + Amount,并将其用作ListBox的
DisplayMemberPath
。另一种解决方案是在GetMaterialsAfterNormalBatch中创建一个
new ObservableCollection
,并且不返回传入的allMaterials集合。然后UI更新将通过CollectionChanged进行。但实际上,如果只有项目成员数据更改,则不建议重新创建新集合。ttcibm8c2#
根据注解中的附加说明,我猜您需要使用如下代码:
字符串
**P.S.**但是我仍然对“Get”方法有很大的怀疑。根据参数和名称判断,你在其中得到了Materials集合的一个投影。下一次调用它时,它将是一个投影的投影,然后投影链将不断增长。
如果你能解释一下这个方法背后的逻辑,也许我能提出一个更好的解决方案来实现它。
在添加物料分类代码后添加到答案。
1.取Mshu基类代码BaseInpc and RelayCommand classes.
1.加入性质以显示“材料”显示视图,并在其变更时显示通知。
型
1.“GetMaterialsAfterNormalBatch”方法不应返回集合,它只是修改传递给它的集合。
型
型
1.该命令不需要更改集合本身。您只需要更改其元素的属性值:
型
型