MVVM サービスと RIA サービスを使用したさまざまなバインディング アプローチの長所と短所
-
25-09-2019 - |
質問
私は、LoadOperation の Entities を使用して View Model の CollectionViewSource のソースとなる IEnumerable を返すアプリケーションを構築しています。私は現在、このアプローチの潜在的な落とし穴を発見しています。Silverlight クライアントにエンティティを追加するとき、新しいエンティティを送信してからリロードするか、バインドしている項目の別のコレクションを維持しない限り、これらのエンティティを表示できません。
私が実際に考えている選択肢は次のとおりです。
- ViewModel の CollectionViewSource プロパティのソースとして使用する ObservableCollection を追加します。これにより、DomainContext と ObservableCollection の両方に同時に追加して、コレクションの同期を保つことができます。
- EntitySet へのバインドを直接変更し、CollectionViewSource でフィルタリングを提供するフィルタリング イベント ハンドラーを追加します。
誰かがそれぞれの長所/短所についてヒントや考えを持っている場合は、それをいただければ幸いです。特に、どちらか一方を選択した方が、パフォーマンスやプログラミング上の利点があるかどうか疑問に思っています。
解決
私はこのつのアプローチです。まず、表示を参考にdicussこと、をライティングによって異なる変動支援に必要な各手法です。
の基本デモでは、認証済みドメインサービスを返す単一の組織の資源です。まさ4コマンドに保存元に戻す、追加、削除、コレクション、プロパティのSelectedResource.
2つの異なる授業のこのインタフェースを実装する(1混合1生産)。生産だけになってます。通知のアクション(lo.エンティティ)のGetMyResources機能:
public class WorkProvider
{
static WorkContext workContext;
public WorkProvider()
{
if (workContext == null)
workContext = new WorkContext();
}
public void AddResource(Resource resource)
{
workContext.Resources.Add(resource);
}
public void DelResource(Resource resource)
{
workContext.Resources.Remove(resource);
}
public void UndoChanges()
{
workContext.RejectChanges();
}
public void SaveChanges(Action action)
{
workContext.SubmitChanges(so =>
{
if (so.HasError)
// Handle Error
throw so.Error;
else
action();
}, null);
}
public void GetMyResources(Action<IEnumerable<Resource>> action)
{
var query = workContext.GetResourcesQuery()
.Where(r => r.UserName == WebContext.Current.User.Name);
workContext.Load(query, LoadBehavior.MergeIntoCurrent, lo =>
{
if (lo.HasError)
// Handle Error
throw lo.Error;
else
action(lo.Entities);
}, null);
}
}
のViewModel、以下の実施
public class HomeViewModel : ViewModelBase
{
WorkProvider workProvider;
public HomeViewModel()
{
workProvider = new WorkProvider();
}
// _Source is required when returning IEnumerable<T>
ObservableCollection<Resource> _Source;
public CollectionViewSource Resources { get; private set; }
void setupCollections()
{
Resources = new CollectionViewSource();
using (Resources.DeferRefresh())
{
_Source = new ObservableCollection<Resource>();
Resources.Source = _Source;
Resources.GroupDescriptions.Add(new PropertyGroupDescription("Title"));
Resources.SortDescriptions.Add(new SortDescription("Title", ListSortDirection.Ascending));
Resources.SortDescriptions.Add(new SortDescription("Rate", ListSortDirection.Ascending));
}
}
void loadMyResources()
{
workProvider.GetMyResources(results =>
{
using (Resources.DeferRefresh())
{
// This is required when returning IEnumerable<T>
_Source.Clear();
foreach (var result in results)
{
if (!_Source.Contains(result))
_Source.Add(result);
}
}
});
}
Resource _SelectedResource;
public Resource SelectedResource
{
get { return _SelectedResource; }
set
{
if (_SelectedResource != value)
{
_SelectedResource = value;
RaisePropertyChanged("SelectedResource");
}
}
}
public RelayCommand CmdSave { get; private set; }
public RelayCommand CmdUndo { get; private set; }
public RelayCommand CmdAdd { get; private set; }
public RelayCommand CmdDelete { get; private set; }
void setupCommands()
{
CmdSave = new RelayCommand(() =>
{
workProvider.SaveChanges(() =>
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
System.Windows.MessageBox.Show("Saved");
});
});
});
CmdUndo = new RelayCommand(() =>
{
workProvider.UndoChanges();
// This is required when returning IEnumerable<T>
loadMyResources();
});
CmdAdd = new RelayCommand(() =>
{
Resource newResource = new Resource()
{
ResourceID = Guid.NewGuid(),
Rate = 125,
Title = "Staff",
UserName = "jsmith"
};
// This is required when returning IEnumerable<T>
_Source.Add(newResource);
workProvider.AddResource(newResource);
});
CmdDelete = new RelayCommand(() =>
{
// This is required when returning IEnumerable<T>
_Source.Remove(_SelectedResource);
workProvider.DelResource(_SelectedResource);
});
}
}
の代替方法の変更を伴うWorkProviderクラスを次のように、アクション(workContext.資源返される:
public void GetMyResources(Action<IEnumerable<Resource>> action)
{
var query = workContext.GetResourcesQuery()
.Where(r => r.UserName == WebContext.Current.User.Name);
workContext.Load(query, LoadBehavior.MergeIntoCurrent, lo =>
{
if (lo.HasError)
// Handle Error
throw lo.Error;
else
// Notice Changed Enumeration
action(workContext.Resources);
}, null);
}
の変化にviewmodelいて(お知らせの削除を_Source ObservableCollection):
public class HomeViewModel : ViewModelBase
{
WorkProvider workProvider;
public HomeViewModel()
{
workProvider = new WorkProvider();
}
public CollectionViewSource Resources { get; private set; }
void setupCollections()
{
Resources = new CollectionViewSource();
using (Resources.DeferRefresh())
{
Resources.Filter += (s,a) =>
{
a.Accepted = false;
if (s is Resource)
{
Resource res = s as Resource;
if (res.UserName == WebContext.Current.User.Name)
a.Accepted = true;
}
};
Resources.GroupDescriptions.Add(new PropertyGroupDescription("Title"));
Resources.SortDescriptions.Add(new SortDescription("Title", ListSortDirection.Ascending));
Resources.SortDescriptions.Add(new SortDescription("Rate", ListSortDirection.Ascending));
}
}
void loadMyResources()
{
workProvider.GetMyResources(results =>
{
using (Resources.DeferRefresh())
{
Resources.Source = results;
}
});
}
Resource _SelectedResource;
public Resource SelectedResource
{
get { return _SelectedResource; }
set
{
if (_SelectedResource != value)
{
_SelectedResource = value;
RaisePropertyChanged("SelectedResource");
}
}
}
public RelayCommand CmdSave { get; private set; }
public RelayCommand CmdUndo { get; private set; }
public RelayCommand CmdAdd { get; private set; }
public RelayCommand CmdDelete { get; private set; }
void setupCommands()
{
CmdSave = new RelayCommand(() =>
{
workProvider.SaveChanges(() =>
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
System.Windows.MessageBox.Show("Saved");
});
});
});
CmdUndo = new RelayCommand(() =>
{
workProvider.UndoChanges();
Resources.View.Refresh();
});
CmdAdd = new RelayCommand(() =>
{
Resource newResource = new Resource()
{
ResourceID = Guid.NewGuid(),
Rate = 125,
Title = "Staff",
UserName = "jsmith"
};
workProvider.AddResource(newResource);
});
CmdDelete = new RelayCommand(() =>
{
workProvider.DelResource(_SelectedResource);
});
}
}
第二のアプローチのエコを追加する必要があるフィルターイベントハンドラの構成にCollectionViewSource、ひとつと考えられるのであるフィルタリングデータが2時間(1時間のプロトコルやインタフェースを第二の時間のCollectionViewSource)では、以下の特典:ある単一のコレクション-よる経営の収集通知ンプルになります。コレクションは、実際のコレクションに提供するサーバー、管理を追加/削除プがあるので、あなたは、あなたがいない機会が忘れの追加と削除団体からの正しいコレクションを始めるための追加-削除機能を提出する。
の最終のものかを確認する必要は次の通りです:にcollectionviewsourceでは、私の理解いただくことを利用DeferRefresh()が複数の変更に影響を与える。このうのを防ぐ必要に更新さ断時の内部変化の原因となりの更新などの設定の仕分け、グループ化。でも重要な金がかかる場合があります。ます。リフレッシュ()がこのUIへの過程の一部を更新。きます。ます。リフレッシュ()はますます重要に注のDeferRefresh()で何をすべきかを考えることが重要でUIでupdateに対して防止をUIです。
わからない場合が他の人のお役に立つことが希望です。私のエコな時代を通じてこれらのようです。場合は明示またはその他のものに加え、お気軽ください。
他のヒント
ライアン、ちょっと調べてみる価値はあるかもしれない コレクションのバインディングに関するこの投稿 (および関連するもののいくつか)。あなたの実装は確かに合理的なものですが、フレームワークレベルですでに解決されているいくつかの問題と格闘していることがわかります。