【问题标题】:MVC 6 - Dropdown in header, value accessible from all controllers?MVC 6 - 标题中的下拉列表,可从所有控制器访问的值?
【发布时间】:2017-02-26 13:02:32
【问题描述】:

对 MVC 还很陌生,但我遇到了一些绊脚石,我认为这很简单。

我的 _Layout 中有部分 _Header 视图。在这里,我想显示一个下拉列表,其中包含基于登录用户填充的项目列表。

在我项目的每个控制器中,我想检索选定的值并显示依赖于此的数据。

我尝试了几次,但总是卡在不同的位置。我正在创建一个基本控制器来保存我的项目列表和选定的项目值(都是静态的)。然后,在我的 AccountController 中,我可以在登录时填充这些值。我可以从我的其他控制器访问所有这些...但是如何在我的_Header 中填充下拉列表?我似乎无权访问这些。我什至走的是正确的路线吗?在经典的 ASP 中,我会将这些存储在视图状态中..

更新 - 根据 Marco 的建议

从控制器设置的 viewbag 值在视图中不可用(尽管可以访问) - 它总是返回 null。为了让事情更简单,我暂时将选择列表更改为简单的 int。代码如下

ViewPageBase -

public abstract class ViewPageBase : RazorPage
{
    public int SelectedValue
    {
        get { return (ViewBag.SelectedValue == null ? 0 : ViewBag.SelectedValue); }
        set { ViewBag.SelectedValue = value; }
    }
}

public abstract class ViewPageBase<TModel> : RazorPage<TModel>
{
    public int SelectedValue
    {
        get { return (ViewBag.SelectedValue == null ? 0 : ViewBag.SelectedValue); }
        set { ViewBag.SelectedValue = value; }
    }
}

基础控制器 -

public class BaseController : Controller
{
    public int SelectedValue
    {
        get { return (ViewBag.SelectedValue == null ? 0 : ViewBag.SelectedValue); }
        set { ViewBag.SelectedValue = value; }
    }
}

AccountController : BaseController -

public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;

        if (!ModelState.IsValid)
            return View(model);

        var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, false);

        if (result.Succeeded)
        {
            SelectedValue = 10;
            _logger.LogInformation(1, "User logged in.");
            return RedirectToLocal(returnUrl);
        }

        if (result.IsLockedOut)
        {
            _logger.LogWarning(2, "User account locked out.");
            return View("Lock");
        }
        ModelState.AddModelError(string.Empty, "Invalid login attempt.");
        return View(model);
    }

_布局 -

@{ await Html.RenderPartialAsync("_Header"); }

在 _Header 中,我只是想读取 @SelectedValue 但这始终为空(在我的情况下为 0,因为我正在执行空检查)。

【问题讨论】:

  • 您可以通过ViewBag 将数据放入您的_Layout(以及标题)。或者,您可以将 _Header 作为部分操作(而不是部分视图),在这种情况下,它将调用控制器并获取所需的任何数据。
  • "在我的 AccountController 中,我可以在 login" 上填充这些值 - 这就是无状态 MVC 控制器操作的工作方式。

标签: asp.net-mvc asp.net-core-mvc


【解决方案1】:

您可以使用以下方法

  1. 在局部视图中添加 HTML 下拉菜单。
  2. 编写一个函数来进行 ajax 调用并获取值并使用 jquery 将下拉列表与这些值绑定。它应该在页面加载时访问服务器(document.ready)。
  3. 现在将更改事件添加到您的下拉列表中,并在每次更改时进行 ajax 调用并在会话中设置选定的值。
  4. 所以现在您将在每个控制器上拥有这些选定的值,直到您存在会话。

我认为这有帮助。

【讨论】:

    【解决方案2】:

    您需要创建一个自定义剃须刀视图基类,您的所有视图都将从该基类继承。这是有关如何完成的文章:

    http://haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-view.aspx/

    基本上,您将创建一个继承自 WebViewPage 的类。在此类中,您将声明一个包含您的选择列表的属性:

    public abstract class CustomWebViewPage : WebViewPage
    {
        private SelectList _mySelectList;
    
        public SelectList MySelectList
        {
            get
            {
                try
                {
                    _mySelectList = (SelectList)ViewBag.MySelectList;
                }
                catch (Exception)
                {
                    _mySelectList = null;
                }
                return _mySelectList;
            }
        }
    }
    
    public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel>
    {
        private SelectList _mySelectList;
    
        public SelectList MySelectList
        {
            get
            {
                try
                {
                    _mySelectList = (SelectList)ViewBag.MySelectList;
                }
                catch (Exception)
                {
                    _mySelectList = null;
                }
                return _mySelectList;
            }
        }
    }
    

    如您所见,在这种情况下,选择列表的值是从 ViewBag 中检索的。不一定是这样,但这对我来说是最容易展示这个想法的。您可以在您制作的基本控制器内设置视图包的值。现在每个视图都可以访问这个属性。

    您唯一要做的就是告诉您的解决方案使用您的新类构建 MVC 视图。您可以通过将以下行添加到您的 Web 配置来做到这一点:

    <pages pageBaseType="Project.Namespace.Views.CustomWebViewPage">
    

    其中 Project.Namespace.Views 是新自定义类所在的命名空间。请注意,这条线位于

    <system.web.webPages.razor> 
    

    标签,它需要添加到与您的视图相关的所有 web.configs - Views 文件夹中的 web.configs。

    所有这些都完成后,您可以简单地执行以下操作:

    @MySelectList
    

    在您的视图中访问您的选择列表。祝你好运!

    【讨论】:

    • 感谢您的建议...我已经尝试过了,但是 ViewBag 的值似乎没有得到体现,而且我总是得到空值。当我使用 MVC6 时,我已经根据stackoverflow.com/questions/32563279/… 中描述的解决方案修改了您的建议。这样做的原因是我可以从所有视图中访问该值,但如果我从我的帐户控制器中设置该值,它在我的视图中仍然显示为 null。
    • @xemmers 您的帐户控制器是否继承自您的基本控制器?
    • @Marco 是的,ViewBag 值是在基本控制器中设置的,所有控制器都继承了它。但在视图中仅显示为 null。我可以看到控制器中正确设置的值,也可以从其他控制器中检索该值,因为它是静态的,这是正确的。需要明确的是,在 BaseController 中我应该设置 ViewBag.whatever 正确?
    • @xemmers 您必须将 ViewBag.MySelectList 的值设置为您的 SelectList。它必须是 SelectList 类型,因为如果您在 try catch 块中查看我的代码,我正在尝试将视图包转换为 SelectList。如果您将视图包值设置为某个不是 SelectList 类型的对象,那么它显然将不起作用......并且 try catch 将抑制任何错误......
    • @Marco - 我实际上只是在尝试使用 int 来消除任何这些问题。我已经用我的代码更新了原始问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    相关资源
    最近更新 更多