ninjectを使用してページをロードするMainPageを使用してWPFWebアプリケーションに取り組んでいます。
基本的に、ユーザーが複合キーの値を更新したためにIDが変更されたことをNavigationServiceに通知する方法があるかどうか悩んでいます。
もう少し説明するように頑張ります。私のMultiTagPageにはMultiTagViewModelがあり、(MultiTagDef、Key、Value)で構成されるmultitagvalueを表示します。同じキーとMultiTagDefを持つ他の値を持つDataGridもあります。これらの値の1つをダブルクリックすると、対応するマルチタグ値が代わりに表示されます。
データベースでは、マルチタグ値は複合キー(Multitagdef.Name、key、value)とともに保存されます。したがって、誰かがマルチタグ値を更新すると、IDが変更され(たとえば、(A、B、C)から(A、B、D)に)保存され、ユーザーがデータグリッド内の別のマルチタグ値に進むと(A、B、E)そしておそらくそのオブジェクトを削除してから、navigationserviceは(A、B、D)ではなく(A、B、C)をロードしようとします。
アーキテクチャは、もちろん変更されないID列を持つオブジェクト用に設計されています。残念ながら、この場合、ID列を追加することはできません。それで、誰かがこれを解決する方法の提案を持っていますか?誰かが保存するたびにページをリロードしようとする必要がありますか、それとも現在のオブジェクトがIDを変更したことをNavigationServiceに伝えることができますか?
今、コード:
MainPageから:
public partial class MainPage : IUIService
{
public static readonly DependencyProperty MainModelProperty = PropertyHelper.Register<MainPage>(x => x.MainModel);
public MainModel MainModel
{
get { return (MainModel)GetValue(MainModelProperty); }
set { SetValue(MainModelProperty, value); }
}
private static readonly ILog log = LogManager.GetLogger(typeof(MainPage));
public MainPage()
{
// Make doubly sure...
ShowsNavigationUI = false;
InitializeComponent();
App.Kernel.Rebind<IUIService>().ToConstant(this);
MainModel = App.Kernel.Get<MainModel>();
WindowTitle = MainModel.Title;
ContentFrame.Navigating += Navigating;
ContentFrame.Navigated += Navigated;
ContentFrame.NavigationFailed += NavigationFailed;
}
private void Navigating(object sender, NavigatingCancelEventArgs args)
{
object dataContext = null;
if(ContentFrame.Content is FrameworkElement) {
dataContext = ((FrameworkElement)ContentFrame.Content).DataContext;
} else if(ContentFrame.Content is FrameworkContentElement) {
dataContext = ((FrameworkContentElement)ContentFrame.Content).DataContext;
}
if(dataContext is ISaveable && ((ISaveable)dataContext).NeedsSave) {
if(MessageControl.UnsavedSync() != MessageControl.Button.Yes) {
args.Cancel = true;
}
}
}
private void Navigated(object sender, NavigationEventArgs e)
{
var mi = e.ExtraData as MenuItemModel;
if(mi == null) {
var page = e.Content as IMenuItemPage;
if(page != null) {
mi = page.MenuItem;
}
if(mi == null) {
log.DebugFormat("Navigated to {0} ({1}) without menu item", e.Content, e.Uri);
return;
}
}
MainModel.CurrentMenuItem = mi;
if(mi.Type != MenuItemType.Folder) {
Settings.Default.AddRecentMenuItem(new RecentMenuItem(mi.MenuItem));
}
}
#region Generic Edit command
private void EditCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.Handled = true;
e.CanExecute = false;
var param = Unwrap(e.Parameter);
var paramType = GetEditType(param);
if(paramType == null || !editPages.ContainsKey(paramType)) {
return;
}
e.CanExecute = ToConstructorArgument(param) != null;
}
private void EditExecuted(object sender, ExecutedRoutedEventArgs e)
{
Edit(e.Parameter);
}
private void Edit(object param)
{
var paramType = GetEditType(param);
if(paramType == null || !editPages.ContainsKey(paramType)) {
log.WarnFormat("Page for param {0} (type {1}) not found", param, paramType);
return;
}
if(param is IList) {
var list = (IList)param;
if(list.Count > 1000) {
Show("Too many items selected", "Please select no more than 1000 items at a time", messageTheme: MessageTheme.Warning);
return;
}
}
var arg = ToConstructorArgument(param);
if(arg == null) {
log.Warn("Unexpected parameter " + param + " supplied to EditExecuted");
return;
}
var pageType = editPages[paramType];
try {
log.DebugFormat("Got a parameter of type {0}, navigating to edit page {1}", param.GetType(), pageType);
Navigate(MakePage(pageType, arg));
} catch(Exception ex) {
log.Error("Unable to load edit page for parameter " + param, ex);
}
}
private static Page MakePage(Type pageType, params IParameter[] p)
{
var page = (Page)App.Kernel.Get(pageType, p);
var dp = ClientUtil.GetViewModelProperty(page.GetType());
if(dp != null) {
page.Loaded += (o, args) => {
var skrap = App.Kernel.Get(dp.PropertyType, p);
page.SetValue(dp, App.Kernel.Get(dp.PropertyType, p));
};
page.Unloaded += (o, args) => {
try {
page.ClearValue(dp);
} catch(Exception e) {
// Often happens when datagrid is in edit mode when navigating away from page:
// http://connect.microsoft.com/VisualStudio/feedback/details/571967/wpf-datagrid-causes-crash-with-sorting-is-not-allowed-during-an-addnew-or-edititem-transaction
log.Warn("Error while unloading page", e);
}
};
ViewModelBehavior.SetUpdateUIError(page, true);
}
return page;
}
#endregion
#region Navigate command
private void NavigateCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = e.Parameter is Type;
e.Handled = true;
}
private void NavigateExecuted(object sender, ExecutedRoutedEventArgs e)
{
var type = e.Parameter as Type;
if(type == null) {
return;
}
Navigate(MakePage(type));
e.Handled = true;
}
#endregion
#region IUIService implementation
public void Navigate(Type type, params Tuple<string, object>[] parameters)
{
Navigate(MakePage(type, parameters.Select(x => new ConstructorArgument(x.Item1, x.Item2)).ToArray()));
}
public void Navigate(Type type, MenuItemModel menuItem, params Tuple<string, object>[] parameters)
{
Navigate(MakePage(type, parameters.Select(x => new ConstructorArgument(x.Item1, x.Item2))
.Prepend(new ConstructorArgument("menuItem", menuItem))
.Prepend(new ConstructorArgument("props", menuItem.Params))
.ToArray()),
menuItem);
}
public void Navigate(Page content, object extraData = null)
{
if(ContentFrame != null) {
if(ContentFrame.Content is DependencyObject) {
foreach(var dg in WpfUtil.FindDescendants<DataGrid>((DependencyObject)ContentFrame.Content)) {
while(!dg.CommitEdit()) { /* Keep committing */ }
}
}
ContentFrame.Navigate(content, extraData);
}
}
public bool NavigateBack()
{
if(ContentFrame != null && ContentFrame.CanGoBack) {
ContentFrame.GoBack();
return true;
}
if(NavigationService != null && NavigationService.CanGoBack) {
NavigationService.GoBack();
return true;
}
return false;
}
}
さらに詳しい情報が必要な場合は教えてください。