私は何度も頭を叩いてきました、私は私が直面している問題を回避することができないようです。
Scenario :
私はSalesOrderページを持っています。このページを使用して、新しい販売注文を作成したり、既存の販売注文を編集したりしようとしています。SalesOrder Pageホスト、現在の販売注文にバインドする他のコントロール、RadGridViewおよびDataForm。どちらもMVVMの同じObservableコレクションにバインドします。
私が直面している問題は、
1)DataFormとグリッドはコレクションにバインドされていますが、DataForm編集コマンドにバインドされている編集ボタンは無効になっています。新規ボタンのみが有効になります。
2)データフォームに新しいアイテムを追加すると、Edit
ボタンが有効になりますが、どの行を選択しても、挿入された最初の行は常に編集され、行を挿入しない限り、既存の行を編集することはできません。DataFormはコレクション内の既存の行を実際には認識していないようです!!!
My Implimentation :
私はMVVM-lightを使用しており、以下は私のコードの関連するチャンクです:
**ViewModel**
以下qsdcvSOPDoc
はQueryableSouceDomainCollectionView(mvvmのドメインデータソースのラッパー)です。モデルの販売注文エンティティは呼び出されますSOPDoc
public const string qsdcvSOPDocPropertyName = "qsdcvSOPDoc";
private QueryableDomainServiceCollectionView<SOPDoc> _qsdcvSOPDoc;
public QueryableDomainServiceCollectionView<SOPDoc> qsdcvSOPDoc
{
get
{
return _qsdcvSOPDoc;
}
set
{
if (_qsdcvSOPDoc == value)
{
return;
}
var oldValue = _qsdcvSOPDoc;
_qsdcvSOPDoc = value;
RaisePropertyChanged(qsdcvSOPDocPropertyName, oldValue, value, true);
以下ocSalesOrderItemsList
は、SOPDocのIEnumerableの子エンティティによって入力されるObserable Collectionです。ここで、はSOPDoc.SOPDocDetailsです。
public const string ocSalesOrderItemsListPropertyName = "ocSalesOrderItemsList";
private ObservableCollection<SOPDocDetail> _ocSalesOrderItemsList;
public ObservableCollection<SOPDocDetail> ocSalesOrderItemsList
{
get
{
return _ocSalesOrderItemsList;
}
set
{
if (_ocSalesOrderItemsList == value)
{
return;
}
var oldValue = _ocSalesOrderItemsList;
_ocSalesOrderItemsList = value;
RaisePropertyChanged(ocSalesOrderItemsListPropertyName, oldValue, value, true);
}
}
qsdcvSOPDoc
データが読み込まれると、エンティティentCurrentOrder
に現在の販売注文が入力され、ビューのさまざまなコントロールがこれにバインドされます。
public const string entCurrentOrderPropertyName = "entCurrentOrder";
private SOPDoc _entCurrentOrder; public SOPDoc entCurrentOrder
{
get
{
return _entCurrentOrder;
}
set
{
if (_entCurrentOrder == value)
{
return;
}
_entCurrentOrder = value;
RaisePropertyChanged(entCurrentOrderPropertyName);
}
}
PageMode
このページに移動する前にが設定され、これは「新規」または「編集」のいずれかに設定され、ロードおよび保存コマンドを実行するためのチェックとして、またデフォルト値を設定するいくつかのイベントをトリガーするのに役立ちます。
public const string PageModePropertyName = "PageMode";
private string _pageMode;
public string PageMode
{
get
{
return _pageMode;
}
set
{
if (_pageMode == value)
{
return;
}
_pageMode = value;
RaisePropertyChanged(PageModePropertyName);
}
}
CurrentSalesOrderId
このページに移動しているときに設定されます。
public const string CurrentSalesOrderIdPropertyName = "CurrentSalesOrderId";
private int _currentSalesOrderId;
public int CurrentSalesOrderId
{
get
{
return _currentSalesOrderId;
}
set
{
if (_currentSalesOrderId == value)
{
return;
}
var oldValue = _currentSalesOrderId;
_currentSalesOrderId = value;
RaisePropertyChanged(CurrentSalesOrderIdPropertyName, oldValue, value, true);
}
}
Constructor of ViewModel
public SalesOrderViewModel()
{
ctx = new KERPDomainContext();
var ctxDetail = new KERPDomainContext();
qry = ctx.GetSalesOrderByIdQuery(CurrentSalesOrderId);
qsdcvSOPDoc = new QueryableDomainServiceCollectionView<SOPDoc>(ctx, qry);
qsdcvSOPDoc.Load();
qsdcvSOPDoc.LoadedData += qsdcvSOPDoc_LoadedData;
ocSalesOrderItemsList = new ObservableCollection<SOPDocDetail>();
ocSalesOrderItemsList.CollectionChanged += ocSalesOrderItemsList_CollectionChanged; // This will re-calculate the GrossAmount
//Commands Binding
SaveSalesOrder = new RelayCommand(SaveSalesOrderExecute, SaveSalesOrderCanExecute);
}
}
void qsdcvSOPDoc_LoadedData(object sender, LoadedDataEventArgs e)
{
entCurrentOrder = (SOPDoc)e.Entities.FirstOrDefault();
if (PageMode == Enums.SODModes.New.ToString() && CurrentSalesOrderId <= 0)
{ // this is a new Sales Order
if (entCurrentOrder != null)
ocSalesOrderItemsList.AddRange((entCurrentOrder.SOPDocDetails.Where(i => i.IsActive == true))); // Adds all active items to the collection list
// setting some values, the property decleration i omitted here for brevity
GrossAmount = 0;
Carriage = 0;
Discount = 0;
}
if (PageMode == Enums.SODModes.Edit.ToString() && CurrentSalesOrderId > 0)
{
if (entCurrentOrder != null)
{
ocSalesOrderItemsList.AddRange(entCurrentOrder.SOPDocDetails);
GrossAmount = entCurrentOrder.SOPDocDetails.Sum(i => i.NetAmount);
Carriage = entCurrentOrder.Carriage;
Discount = entCurrentOrder.Discount;
}
}
}
意見
ビューには、同じItemSourceとCurrentItemにバインドされたRadGridViewコントロールとdataformコントロールがあります。
<telerik:RadGridView ItemsSource="{Binding ocSalesOrderItemsList}" Grid.Row="1"
AutoExpandGroups="True" AutoGenerateColumns="False" ColumnWidth="*" CurrentItem="{Binding entSOPDocDetail}" IsSynchronizedWithCurrentItem="True" IsReadOnly="False">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="Product Code" DataMemberBinding="{Binding ProductCode}" Width="1.5*"/>
<telerik:GridViewDataColumn Header="Description" DataMemberBinding="{Binding Description}" Width="5*"/>
<telerik:GridViewDataColumn Header="Qty" DataMemberBinding="{Binding Qty}" Width="*"/>
<telerik:GridViewDataColumn Header="UnitType" DataMemberBinding="{Binding UnitType}"/>
<telerik:GridViewDataColumn Header="Unit Price" DataMemberBinding="{Binding UnitPrice}" DataFormatString="{}{0:0,0.00}"/>
<telerik:GridViewDataColumn Header="Line Total" DataMemberBinding="{Binding NetAmount}" DataFormatString="{}{0:0,0.00}"/>
<telerik:GridViewColumn Width="90">
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<telerik:RadButton Content="Delete" Command="telerik:RadGridViewCommands.Delete" CommandParameter="{Binding}" />
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewColumn>
</telerik:RadGridView.Columns>
</telerik:RadGridView>
<telerik:RadDataForm x:Name="dataForm"
ItemsSource="{Binding ocSalesOrderItemsList}"
CommandButtonsVisibility="Cancel,Commit"
AutoGenerateFields="False"
ValidationSummaryVisibility="Collapsed"
EditEnded="RadDataForm_EditEnded"
CurrentItemChanged="OnDataFormCurrentItemChanged"
LabelPosition="Above"
EditTemplate="{StaticResource SOItemsEditTemplate}"
NewItemTemplate="{StaticResource SOItemsEditTemplate}"
VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" CurrentItem="{Binding entSOPDocDetail}"/>
Add
およびEdit
ボタンはDataFormコマンドにバインドされています。
<telerik:RadButton RenderTransformOrigin="0.5,0.5" Style="{StaticResource smallCommandCircleRadButtons}" Tag="EDIT"
Command="telerik:RadDataFormCommands.BeginEdit" CommandTarget="{Binding ElementName=dataForm}" />
<telerik:RadButton RenderTransformOrigin="0.5,0.5" Style="{StaticResource smallCommandCircleRadButtons}" Margin="0,0,40,0" Tag="ADD ITEM"
Command="telerik:RadDataFormCommands.AddNew" CommandTarget="{Binding ElementName=dataForm}" />
繰り返しますが、問題私が直面している問題は、1)DataFormとグリッドがコレクションに正常にバインドされているが、DataForm編集コマンドにバインドされている編集ボタンが無効になっていることです。新規ボタンのみが有効になります。
2)データフォームに新しいアイテムを追加すると、Edit
ボタンが有効になりますが、どの行を選択しても、挿入された最初の行は常に編集され、行を挿入しない限り、既存の行を編集することはできません。DataFormはコレクション内の既存の行を実際には認識していないようです!!!
上記のアプローチに原則的な誤りがあるかもしれないし、アプローチ全体が間違っているかもしれないことを私は知っています、しかしそれが私が助けを求めている理由です!! CRUD、データフォーム、MVVMをサポートするグリッドなど、さまざまなアプローチの提案についての提案をいただければ幸いです。