1

私は何度も頭を叩いてきました、私は私が直面している問題を回避することができないようです。

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をサポートするグリッドなど、さまざまなアプローチの提案についての提案をいただければ幸いです。

4

1 に答える 1

1

さて、ついに私は自分自身で、そして私がSOHereに投稿した別の質問の助けを借りて上記にアプローチする方法を見つけました。

私が実際に行ったことは、DomainContextctxを宣言してから、経由で販売注文をロードしDomainDataSource1、別の方法DomainDataSource2で注文の詳細をロードしました。これらは両方とも、それぞれグリッドとデータフォームにバインドされています。レコードのすべての編集と追加の後ctx.SaveChanges、ロードされたすべてのエンティティへのすべての変更をRia.Entity.AcceptChanges()で保護されたメソッドに保存するように呼び出しました。それでおしまい...

結論:コンテキストにデータをロードするために使用するDomainDataSourceの数に関係なく、それらをすべて一緒に保存する場合は、それらすべてにSINGLEDomainContextを使用します。DomainContexts部分的なSubmitChangesを使用する場合にのみsaperateを使用してください:)。

まだ説明が必要ですか?コメントしてください......。

于 2012-06-21T07:53:18.560 に答える