2

我正在开发一个带有 MainPage 的 WPF Web 应用程序,该应用程序使用 ninject 加载页面。

基本上,如果有一种方法可以告诉 NavigationService 由于用户更新了复合键中的值而导致 Id 发生了变化,我会感到很困惑。

我会尽力解释更多。我的 MultiTagPage 有一个 MultiTagViewModel,它显示了一个由 (MultiTagDef, Key, Value) 组成的多标签值。还有一个具有相同键和 MultiTagDef 的其他值的 DataGrid。如果您双击其中一个值,则会显示相应的多标签值。

在数据库中,多标签值与复合键(Multitagdef.Name、key、value)一起存储。因此,如果有人更新多标签值,则 ID 会更改(例如从 (A, B, C) 更改为 (A, B, D))并保存,然后如果用户继续使用数据网格中的另一个多标签值 (A, B, E)并且可能会删除该对象,然后导航服务尝试加载(A,B,C)而不是(A,B,D)。

该体系结构是为具有 ID 列的对象设计的,该列当然永远不会改变。不幸的是,在这种情况下添加 ID 列不是一个选项。那么有人对如何解决这个问题提出建议吗?每次有人保存时我是否应该尝试重新加载页面,或者我可以告诉 NavigationService 当前对象现在已更改 ID?

现在,代码:

从主页:

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;
    }

}

如果您需要更多信息,请告诉我。

4

0 回答 0