0

我在 ASP.NET MVC 4 项目中使用 DevExpress 控件。

我在GridViewASP.NET MVC 的扩展中使用未绑定的列。在CustomUnboundColumnData事件处理程序中,e.GetListSourceFieldValue总是为我返回 null。

然后,我尝试直接从模型中获取值,而不是调用此方法(请参阅该方法调用上方的注释行),但即使这样有效,它也有副作用,我现在不会讨论.

我正在使用带有 Visual Web Developer Express 2010 版的 ASP.NET MVC 4。我正在为 MVC v12.2.10.0 使用 DevExpress 扩展。

我的操作系统是 Windows 7,64 位。但是,我使用的扩展只是 32 位的。

我无法交付我的整个解决方案,因为它被分解为多个项目,其中大部分都有我为我的客户编写的大量 IP 代码。但这是我的代码中的相关部分。

Index.cshtml (Razor 视图引擎) ------------------------------------------ -------------------------

@model List<GlobalizationUI.Presentation.ViewModels.StringTableRow>

@{
    ViewBag.Title = "Strings";
}

<div id = "pageCaption">Strings</div>

@Html.Partial("_StringsPartial", Model)

_StringsPartial.cshtml (Razor 视图引擎) ------------------------------------------ -------------------------

@using System.Web.UI.WebControls;
@using System.Data;
@model List<GlobalizationUI.Presentation.ViewModels.StringTableRow>

@Html.DevExpress().GridView(settings =>
    {
        settings.Name = "gvStrings";

        settings.CallbackRouteValues = new { Controller = "Strings", Action = "StringsPartial" };

        settings.Width = 1200;

        settings.SettingsPager.Position = PagerPosition.TopAndBottom;
        settings.SettingsPager.FirstPageButton.Visible = true;
        settings.SettingsPager.LastPageButton.Visible = true;
        settings.SettingsPager.PageSizeItemSettings.Visible = true;
        settings.SettingsPager.PageSizeItemSettings.Items = new string[] { "10", "20", "50", "100", "200" };
        settings.SettingsPager.PageSize = 50;

        settings.Settings.ShowFilterRow = true;
        settings.Settings.ShowFilterRowMenu = true;

        settings.CommandColumn.Visible = true;
        settings.CommandColumn.ClearFilterButton.Visible = true;

        settings.Settings.ShowHeaderFilterButton = true;

        settings.KeyFieldName = "ResourceKeyId";

        settings.Columns.Add("Key");

        var categoryColumn = settings.Columns.Add("CategoryId", "Category");
        categoryColumn.ColumnType = MVCxGridViewColumnType.ComboBox;
        var categoryColumnEditProperties = categoryColumn.PropertiesEdit as ComboBoxProperties;
        categoryColumnEditProperties.DataSource = ViewBag.AllCategories;
        categoryColumnEditProperties.TextField = "Name";
        categoryColumnEditProperties.ValueField = "Id";
        categoryColumnEditProperties.ValueType = typeof(long);

        if (Model != null && Model.Count > 0 &&
            Model[0] != null && Model[0].StringValues != null && Model[0].StringValues.Count > 0)
        {
            foreach (var kvp in Model[0].StringValues)
            {
                settings.Columns.Add(col =>
                {
                    col.FieldName = kvp.CultureShortName;
                    col.Caption = kvp.CultureShortName;
                    col.UnboundType = DevExpress.Data.UnboundColumnType.Object;
                    col.SetDataItemTemplateContent(container => { ViewContext.Writer.Write(DataBinder.Eval(container.DataItem, col.FieldName + ".StringValue")); });

                    col.SetEditItemTemplateContent(container =>
                        {
                            Html.DevExpress().TextBox(s =>
                                {
                                    s.Name = string.Format("txt{0}", kvp.CultureShortName);
                                }).Bind(kvp.StringValue).Render();
                        });
                });
            }
        }

        settings.CustomUnboundColumnData = (sender, e) =>
        {
            var fixedColumns = new List<string> { "ResourceKeyId", "Key", "CategoryId" };

            if (!fixedColumns.Contains(e.Column.FieldName))
            {
                if (e.IsGetData)
                {
                    try
                    {
                        // var values = Model[e.ListSourceRowIndex].StringValues;

                        var values = e.GetListSourceFieldValue(e.ListSourceRowIndex, "StringValues") as IList<GlobalizationUI.Presentation.ViewModels.CultureNameAndStringValue>;

                        if (values != null)
                        {
                            var value = values.FirstOrDefault(pair => pair.CultureShortName == e.Column.FieldName);

                            var defaultValue = default(GlobalizationUI.Presentation.ViewModels.CultureNameAndStringValue);

                            e.Value = value.Equals(defaultValue) ? defaultValue : new GlobalizationUI.Presentation.ViewModels.CultureNameAndStringValue();
                        }
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debugger.Break();
                        System.Diagnostics.Debug.Print(ex.ToString());
                    }
                }
            }
        };

        foreach (GridViewDataColumn column in settings.Columns)
        {
            column.Settings.HeaderFilterMode = HeaderFilterMode.CheckedList;
        }

        settings.SettingsEditing.AddNewRowRouteValues = new { Controller = "Strings", Action = "CreateNew" };
        settings.SettingsEditing.UpdateRowRouteValues = new { Controller = "Strings", Action = "Edit" };
        settings.SettingsEditing.DeleteRowRouteValues = new { Controller = "Strings", Action = "Delete" };

        settings.SettingsEditing.Mode = GridViewEditingMode.Inline;

        settings.SettingsBehavior.ConfirmDelete = true;

        settings.CommandColumn.Visible = true;
        settings.CommandColumn.NewButton.Visible = true;
        settings.CommandColumn.EditButton.Visible = true;
        settings.CommandColumn.UpdateButton.Visible = true;
        settings.CommandColumn.DeleteButton.Visible = true;

    }).Bind(Model).GetHtml()

字符串控制器------------------------------------------------- ------------------

using System.Data;
using System.Web.Mvc;
using GlobalizationUI.BusinessObjects;
using Resources.BaseServices.Caching;
using System.Collections.Generic;
using System.ComponentModel;
using GlobalizationUI.Presentation.ViewModels;
using Resources.Util;

namespace GlobalizationUI.Presentation.Controllers
{
    public class StringsController : Controller
    {
        private static string CacheKey_StringTable = "CacheKey_StringTable";
        private static string CacheKey_AllCategories = "CacheKey_AllCategories";
        private static object padLock = new object();

        public ActionResult Index()
        {
            var stringTable = GetStringTable();

            ViewBag.AllCategories = GetCategoryList();

            return View(stringTable);
        }

        public ActionResult StringsPartial()
        {
            var stringTable = GetStringTable();

            ViewBag.AllCategories = GetCategoryList();

            return PartialView("_StringsPartial", stringTable);
        }

        [HttpPost]
        public ActionResult CreateNew(StringTableRow row)
        {
            System.Diagnostics.Debugger.Break();

            foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(row))
            {
                System.Diagnostics.Debug.Print(prop.Name);
            }

            return Content("Hello, there!");
        }

        [HttpPost]
        public ActionResult Edit(DataRow row)
        {
            return new EmptyResult();
        }

        [HttpPost]
        public ActionResult Delete(long resourceKeyId)
        {
            return new EmptyResult();
        }

        private IEnumerable<Category> GetCategoryList()
        {
            lock (padLock)
            {
                if (CacheManager.Contains(CacheKey_AllCategories))
                {
                    return CacheManager.Get<IEnumerable<Category>>(CacheKey_AllCategories);
                }
            }

            var list = Category.All;

            lock (padLock)
            {
                CacheManager.Add(CacheKey_AllCategories, list);
            }

            return list;
        }

        private List<StringTableRow> GetStringTable()
        {
            List<StringTableRow> stringTable;

            lock (padLock)
            {
                if (CacheManager.Contains(CacheKey_StringTable))
                {
                    return CacheManager.Get<List<StringTableRow>>(CacheKey_StringTable);
                }
            }

            stringTable = new StringTable().ToListOfStringTableRows();

            lock (padLock)
            {
                CacheManager.Add(CacheKey_StringTable, stringTable);
            }

            return stringTable;
        }
    }
}

查看模型------------------------------------------------ ------------------

using System.Collections.Generic;

namespace GlobalizationUI.Presentation.ViewModels
{
    public class StringTableRow
    {
        public long ResourceKeyId { get; set; }

        public string Key { get; set; }

        public long CategoryId { get; set; }

        public List<CultureNameAndStringValue> StringValues { get; set; }
    }
}

namespace GlobalizationUI.Presentation.ViewModels
{
    public class CultureNameAndStringValue
    {
        public CultureNameAndStringValue() : this(null, null) { }

        public CultureNameAndStringValue(string cultureShortName, string stringValue)
        {
            CultureShortName = cultureShortName;

            StringValue = stringValue;
        }

        public string CultureShortName { get; set; }

        public string StringValue { get; set; }
    }
}

模型: - - - - - - - - - - - - - - - - - - - - - - - - ------------------

using System.Data;
using GlobalizationUI.Data;

namespace GlobalizationUI.BusinessObjects
{
    public class StringTable : DataTable
    {
        public StringTable()
        {
            var sql = @"
            declare @stmt nvarchar(max)

            select @stmt =
                isnull(@stmt + ', ', '') +
                'max(case when s.CultureId = ' + cast(c.Id as nvarchar(max)) +
                ' then s.ResourceValue end) as ' + quotename(c.ShortName)
            from Culture as c
            where c.Supported = 1

            select @stmt = '
                select
                    rk.Id AS ResourceKeyId,
                    rk.Name AS [Key],
                    c.Id AS CategoryId,
                    c.Name as CategoryName, ' + @stmt + '
                from StringCategory as sc
                    LEFT OUTER join Category as c on c.Id = sc.CategoryId
                    RIGHT OUTER JOIN ResourceKey as rk on rk.Id = sc.ResourceKeyId
                    inner join Strings as s on s.ResourceKeyId = rk.Id
                group by rk.Id, rk.Name, c.Id, c.Name
                '

            exec sp_executesql @stmt = @stmt;";

            this.Merge(Database.DefaultDatabase.GetDataTable(sql));
        }
    }
}

模型到视图模型的转换:-------------------------------------------- ----------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlTypes;

namespace GlobalizationUI.Presentation.ViewModels
{
    public static class DataTableExtensions
    {
        public static List<StringTableRow> ToListOfStringTableRows(this DataTable dataTable)
        {
            var ret = new List<StringTableRow>();

            if (dataTable == null || dataTable.Rows.Count == 0) return ret;

            foreach (DataRow row in dataTable.Rows)
            {
                StringTableRow stringTableRow = new StringTableRow();

                foreach (DataColumn column in dataTable.Columns)
                {
                    if (string.Compare(column.ColumnName, "ResourceKeyId", true) == 0)
                    {
                        stringTableRow.ResourceKeyId = (long)row[column.ColumnName];
                    }
                    else if (string.Compare(column.ColumnName, "Key", true) == 0)
                    {
                        stringTableRow.Key = (string)row[column.ColumnName];
                    }
                    else if (string.Compare(column.ColumnName, "CategoryId", true) == 0)
                    {
                        var categoryId = row[column.ColumnName];

                        stringTableRow.CategoryId = categoryId == DBNull.Value ? 0 : (long)categoryId;
                    }
                    else if (string.Compare(column.ColumnName, "CategoryName", true) == 0)
                    {
                        continue;
                    }
                    else
                    {
                        if (stringTableRow.StringValues == null)
                            stringTableRow.StringValues = new List<CultureNameAndStringValue>();

                        stringTableRow.StringValues.Add(new CultureNameAndStringValue(column.ColumnName, (string)row[column.ColumnName]));
                    }
                }

                ret.Add(stringTableRow);
            }

            return ret;
        }
    }
}

在此处输入图像描述

用户界面应该看起来有点像上面显示的图片。SQL 查询返回的列数是可变的,具体取决于特定安装/部署/业务客户端支持的文化数量。因此需要使用未绑定的列。

当我将数据直接绑定到 aSystem.Data.DataTable并且没有使用任何未绑定的列时,我不是通过这段代码而是通过旧版本的代码拍摄这张照片的。这一切都很好,直到我不得不在 MVC/服务器端编辑操作中的数据。因此,我从使用 a 切换DataTable到 POCO,并对所有文化使用未绑定的列。

请帮忙。

4

1 回答 1

0

好的,虽然我仅在 2 小时左右前发布了这个问题,但我已经遇到这个问题超过 8 小时了,并且一直在尝试各种方法来解决这个问题。

就在刚才,我做的一件事让这个问题消失了。这里是。

如果您将 DevExpress GridViewExtensionfor ASP.NET MVC 绑定到像我这样的自定义 POCO,并且该 POCO 有一个或多个成员是任何类型的集合,那么,您必须并且绝对必须在构造函数中初始化代表集合的那些属性你的 POCO。

例如,在我的例子中,模型是StringTableRow's 的列表,其中StringTableRow是 POCO。

StringTableRow课堂上,我有一个名为StringValuestype的属性IList<CultureNameAndStringValue>,它是一个集合。StringValues因此,为了让我的代码正常工作,我在类的构造中初始化了属性StringTableRow,一切都开始工作了。

using System.Collections.Generic;

namespace GlobalizationUI.Presentation.ViewModels
{
    public class StringTableRow
    {
        public StringTableRow()
        {
            // I added this ctor and initialized the
            // StringValues property and the broken
            // custom binding to unbound columns started
            // to work.
            StringValues = new List<CultureNameAndStringValue>();
        }

        public long ResourceKeyId { get; set; }

        public string Key { get; set; }

        public long CategoryId { get; set; }

        public IList<CultureNameAndStringValue> StringValues { get; set; }
    }
}
于 2013-09-18T14:18:33.390 回答