我正在使用的应用程序中有两个关键布尔值,以指示订单是否有效以待批准,然后指示该订单是否已被批准。我想要的是,当ObservableCollection的对象中的值更改时,复选框将在两列上更新,以便用户知道订单是否已准备好批准以及是否已经批准。
这些值会在模型中正确更新,并且视图模型中的批准按钮命令会按预期设置批准的布尔值,但是我无法获取复选框来动态更新。当前,它仅通过更改为其他视图然后再更改为订单视图来进行更新。
我仍在学习数据绑定和MVVM模型,因此我尝试了一些实验。到目前为止,我已经尝试了几种不同的方法来尝试获得我想要的行为,但是没有一个奏效。这是视图模型代码:
<UserControl x:Class="US_Wholesale_App_V2.Views.SPSOrderView"
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:US_Wholesale_App_V2.Views"
xmlns:viewModels="clr-namespace:US_Wholesale_App_V2.ViewModels"
xmlns:models="clr-namespace:US_Wholesale_App_V2.Models"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="1100">
<UserControl.Resources>
<DataTemplate DataType="{x:Type viewModels:SPSLineVM}">
<local:SPSLineView/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:CustomerInfoVM}">
<local:CustomerInfoView/>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="AUTO" MinWidth="312"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="AUTO"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel
Orientation="Horizontal"
HorizontalAlignment="Right"
Grid.Row="0"
Grid.Column="0">
<Button
Content="Lines"
Height="20"
Width="75"
Margin="5,5,5,10"
Command="{Binding SPSNavCommand}"
CommandParameter="Lines"/>
<Button
Content="Shipping"
Height="20"
Width="75"
Margin="5,5,5,10"
Command="{Binding SPSNavCommand}"
CommandParameter="Shipping"/>
</StackPanel>
<DataGrid
x:Name="OrderHeaderGrid"
AutoGenerateColumns="False"
Margin="5"
Grid.Row="1"
Grid.Column="0"
ItemsSource="{Binding SpsData}"
SelectedItem="{Binding SelectedOrder, Mode=TwoWay}"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn
Header="PO Number"
x:Name="PONumberCol"
Binding="{Binding PONumber}"/>
<DataGridTextColumn
Header="Customer"
x:Name="CustomerCol"
Binding="{Binding Customer}"/>
<DataGridTextColumn
Header="Retailer PO Number"
x:Name="RetailersPONumberCol"
Binding="{Binding RetailersPONumber}"/>
<DataGridTextColumn
Header="DC Code"
x:Name="DCCodeCol"
Binding="{Binding DCCode}"/>
<DataGridCheckBoxColumn
Binding="{Binding IsValid, Mode=OneWay}"
IsReadOnly="True"/>
<DataGridTemplateColumn
Header="Approve">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
Content="Approve"
Command="{Binding DataContext.ApproveButton, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding SelectedOrder}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridCheckBoxColumn
Binding="{Binding IsApproved, Mode=OneWay}"
IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
<ContentControl
Grid.Row="1"
Grid.Column="1"
Margin="5">
<ContentControl Content="{Binding SPSCurrentVM}"/>
</ContentControl>
</Grid>
</UserControl>
如果有用,这里也是模型的代码。 RGLibrary项目只是我需要的通用类的库,例如SQL连接器或FTP方法。
using RGLibrary;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Threading.Tasks;
namespace US_Wholesale_App_V2.Models
{
public class SPSOrderModel : Observable_Object, IDataErrorInfo
{
private bool _IsApproved;
private string _PONumber;
private string _RetailersPONumber;
private string _PODate;
private string _ShipDate;
private string _CancelDate;
private string _POPurpose;
private string _POType;
private string _VendorNumber;
private string _Customer;
private string _DCCode;
private string _DepartmentNo;
private ObservableCollection<SPSLineModel> _Lines;
private BillingCustomerModel _BillingInfo;
private ShippingCustomerModel _ShippingInfo;
private ShippingChargesModel _Charges;
public bool IsApproved
{
get { return _IsApproved; }
set { _IsApproved = value; }
}
public string PONumber
{
get { return _PONumber; }
set { _PONumber = value; }
}
public string RetailersPONumber
{
get { return _RetailersPONumber; }
set { _RetailersPONumber = value; }
}
public string PODate
{
get { return _PODate; }
set { _PODate = value; }
}
public string ShipDate
{
get { return _ShipDate; }
set { _ShipDate = value; }
}
public string CancelDate
{
get { return _CancelDate; }
set { _CancelDate = value; }
}
public string POPurpose
{
get { return _POPurpose; }
set { _POPurpose = value; }
}
public string POType
{
get { return _POType; }
set { _POType = value; }
}
public string VendorNumber
{
get { return _VendorNumber; }
set { _VendorNumber = value; }
}
public string Customer
{
get { return _Customer; }
set { _Customer = value; }
}
public string DCCode
{
get { return _DCCode; }
set { _DCCode = value; }
}
public string DepartmentNo
{
get { return _DepartmentNo; }
set { _DepartmentNo = value; }
}
public ObservableCollection<SPSLineModel> Lines
{
get { return _Lines; }
set { _Lines = value; }
}
public BillingCustomerModel BillingInfo
{
get { return _BillingInfo; }
set { _BillingInfo = value; }
}
public ShippingCustomerModel ShippingInfo
{
get { return _ShippingInfo; }
set { _ShippingInfo = value; }
}
public ShippingChargesModel Charges
{
get { return _Charges; }
set { _Charges = value; }
}
public string Error
{
get
{
var errorMsg = new StringBuilder();
if (string.IsNullOrWhiteSpace(DepartmentNo))
errorMsg.AppendLine("The department number for this order cannot be blank");
if (string.IsNullOrWhiteSpace(PODate))
errorMsg.AppendLine("You must enter a purchase order date");
else if (!DateValidate("PODate", PODate))
errorMsg.AppendLine("The PO date format must be MM/DD/YYY");
if (string.IsNullOrWhiteSpace(CancelDate))
errorMsg.AppendLine("You must enter a cancellation date");
else if (!DateValidate("CancelDate", CancelDate))
errorMsg.AppendLine("The cancellation date format must be MM/DD/YYY");
if (string.IsNullOrWhiteSpace(ShipDate))
errorMsg.AppendLine("You must enter a shipment date");
else if (!DateValidate("ShipDate", ShipDate))
errorMsg.AppendLine("The shipment date format must be MM/DD/YYY");
if (string.IsNullOrWhiteSpace(DCCode))
errorMsg.AppendLine("You must enter a DC code");
if (Lines.Any(p => !p.IsValid))
errorMsg.AppendLine("You must correct all errors in the purchase order lines, or remove any lines with errors");
if (SumDispatch(Lines) < 1)
errorMsg.AppendLine("The total dispatch quantity must be at least 1");
return errorMsg.ToString();
}
}
public bool IsValid
{
get
{
bool check = true;
if (IsHeaderValid == false)
check = false;
if (BillingValid == false)
check = false;
if (ShippingValid == false)
check = false;
if (ChargesValid == false)
check = false;
if (LinesValid == false)
check = false;
return check;
}
}
public bool BillingValid
{
get
{
if (BillingInfo != null)
return BillingInfo.IsValid;
else
return false;
}
}
public bool ShippingValid
{
get
{
if (ShippingInfo != null)
return ShippingInfo.IsValid;
else
return false;
}
}
public bool ChargesValid
{
get
{
if (Charges != null)
return Charges.IsValid;
else
return false;
}
}
public bool LinesValid
{
get
{
bool check = true;
if (Lines.Any(l => l.IsValid == false))
check = false;
return check;
}
}
public bool IsHeaderValid
{
get
{
bool check = true;
if (string.IsNullOrWhiteSpace(PODate))
check = false;
if (!DateValidate("PODate", PODate))
check = false;
if (string.IsNullOrWhiteSpace(CancelDate))
check = false;
if (!DateValidate("CancelDate", CancelDate))
check = false;
if (string.IsNullOrWhiteSpace(ShipDate))
check = false;
if (!DateValidate("ShipDate", ShipDate))
check = false;
if (string.IsNullOrWhiteSpace(DCCode))
check = false;
if (Lines.Any(p => !p.IsValid))
check = false;
if (SumDispatch(Lines) < 1)
check = false;
if (string.IsNullOrWhiteSpace(DepartmentNo))
check = false;
return check;
}
}
public string this[string name]
{
get
{
string result = null;
if (name == "PODate")
{
if (string.IsNullOrWhiteSpace(PODate))
result = "You must enter a date";
else if (!DateValidate("PODate", PODate))
result = "Date format must be MM/DD/YYY";
}
if (name == "CancelDate")
{
if (string.IsNullOrWhiteSpace(CancelDate))
result = "You must enter a date";
else if (!DateValidate("CancelDate", CancelDate))
result = "Date format must be MM/DD/YYY";
}
if (name == "ShipDate")
{
if (string.IsNullOrWhiteSpace(ShipDate))
result = "You must enter a date";
else if (!DateValidate("ShipDate", ShipDate))
result = "Date format must be MM/DD/YYY";
}
if (name == "DCCode")
{
if (string.IsNullOrWhiteSpace(DCCode))
result = "You must enter a DC code";
}
return result;
}
}
private static bool DateValidate(string sender, object value)
{
bool check = true;
if (sender == "PODate" || sender == "CancelDate" || sender == "ShipDate")
{
string _date = value.ToString();
string _expression = @"(([0]\d)|(11|12))\/(([012]\d)|(30|31))\/(20)\d{2}";
Regex _Regex = new Regex(_expression);
Match _match = _Regex.Match(_date);
if (!_match.Success)
check = false;
}
return check;
}
private static int SumDispatch(ObservableCollection<SPSLineModel> lines)
{
int dispatchQty = 0;
foreach (SPSLineModel line in lines)
{
dispatchQty += line.DispatchQty;
}
return dispatchQty;
}
}
}
正如问题中提到的最大,我需要在IsApproved和IsValid字段上实现PropertyChanged事件。对于IsApproved,这非常简单,因为我可以重用继承的Observable Object类中的事件: