0

わかりました..保存時にコントローラーに戻すインターフェイスがあります(アイデアを理解するためにほとんどを削除しています)。必要に応じて詳細を追加できますが、全員を圧倒したくありません。

public interface IProjectElement
{        
    string Name { get; set; }
    int ElementTypeID { get; set; }
    ...
}
public class BaseProjectElement : IProjectElement
{

    public int ElementTypeID { get; set; }
    public string AdditionalInformation { get; set; }
    ... 
}    

そして、私はインターフェースのいくつかの実装を持っていますが、ここに例があります...

public class SQLElement : BaseProjectElement
{
    public int? DatabasePlatformID { get; set; }
}

Global.asax 内から - 開始

ModelBinders.Binders.Add(typeof(IProjectElement), new ProjectElementModelBinder());

それでは本題です。以下のコードは、オブジェクトのタイプを判別し、適切なオブジェクトを作成します。私が思うに、すべての値が bindingContent.ValueProvider データで送信されることがわかりますが、興味深いのは、プロパティ コレクションにはインターフェイスの値のみがリストされていることです。base.CreateModel は必要な型を作成しますが、インターフェイスからのデータをオブジェクトに入力するだけです。DatabasePlatformID を設定している場所に追加のプロパティを設定する醜いコードを使用して回避できますが、一部のクラスにはいくつかの追加のプロパティがあります。私はおそらくここで明らかな何かを見逃しています。これは、このような追加のプロパティを設定するのはあまり保守的ではありません。

public class ProjectElementModelBinder : DefaultModelBinder 
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        string modelName = bindingContext.ModelName;
        var elementType = (int)bindingContext.ValueProvider.GetValue(string.Format("{0}.ElementType", modelName)).ConvertTo(typeof(int));
        Type instantiationType = null;
        if (elementType == 1)
        {
            instantiationType = typeof(IISElement);
        }
        else if (elementType == 2)
        {
            instantiationType = typeof(SharePointElement);
        }
        else if (elementType == 3)
        {
            instantiationType = typeof(SQLElement);
        }
        else if (elementType == 12)
        {
            instantiationType = typeof(SharedElement);
        }
        else
        {
            instantiationType = typeof(BaseProjectElement);
        }
        var obj = base.CreateModel(controllerContext, bindingContext, instantiationType);
        if (elementType == 3)
        {
            PropertyInfo pi = obj.GetType().GetProperty("DatabasePlatformID");
            int databasePlatformID = (int)bindingContext.ValueProvider.GetValue(string.Format("{0}.DatabasePlatformID", modelName)).ConvertTo(typeof(int));
            pi.SetValue(obj, databasePlatformID, null);
        }
        return obj;
    }
}

他のどこでも見られるコードを使用してそれを実行しようとしたことに注意してください。

        var obj=Activator.CreateInstance(instantiationType);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, instantiationType);
        bindingContext.ModelMetadata.Model = obj;
        return obj;

これが私のコントローラーです

public ActionResult SaveElements(Guid projectID, List<IProjectElement> selectedElements, List<ProjectElementRelationshipsDAO> selectedRelationships)
    {
        using (ManagedHostingHelper helper = new ManagedHostingHelper())
        {
            BasePageViewModel viewModel = helper.SaveElements(projectID, selectedElements, selectedRelationships);
            return Json(new
            {
                ViewModel = viewModel,
                JsonRequestBehavior.AllowGet
            });
        } 
    }

最後に、コントローラーを呼び出す JavaScript を次に示します。ノックアウト.jsの使用..

self.SaveElements = function () {
    var saveURL = new UrlHelper().SaveElements();
        data: ko.toJSON({ projectID: self.ProjectID(), selectedElements: self.SelectedElements(), selectedRelationships: self.SelectedRelationships() }),
        type: "post", contentType: "application/json",
        success: function (result) {
            if (result.ReturnStatus == true) {
                self.GoForward();
            }
            else { alert('error'); }
        }
    });
};

SelectedElements は、knockout.js の observableArray です。以下は、渡される可能性のある JavaScript オブジェクトです。この配列は、IProjectElement を実装する要素のコレクションを保持することに注意してください。また、すべての異なる型を示しているわけではありませんが、それらはすべて基本的なデータ セットを持ち、追加のプロパティを追加します。 .

// base class - see class diagram in folder as types should match this fairly closely
function BaseProjectElement(data) {
    var self = this;
    self.ProjectElementID = ko.observable(data.ProjectElementID);
    self.ElementName = ko.observable(data.ElementName);
    ... more properties
    self.BaseElementValidationGroup = ko.validatedObservable({
        Name: self.Name
    });
    self.IsBaseElementValid = ko.computed(function () {
        return self.BaseElementValidationGroup().errors().length == 0;
    });
};
function SQLElement(data) {
    var self = this;
    ko.utils.extend(self, new BaseProjectElement(data));
    self.DatabasePlatformID = ko.observable(data.DatabasePlatformID).extend({ required: { params: true, message: ' ' } });
    self.SQLElementValidationGroup = ko.validatedObservable({
        DatabasePlatformID: self.DatabasePlatformID
    });
    self.IsSQLElementValid = ko.computed(function () {
        return (self.SQLElementValidationGroup().errors().length == 0) && self.IsBaseElementValid();
    });
};
4

1 に答える 1

0

OK.. ある時点でこれと似たようなことをしたと思ったが、ここでうまくいった.. ModelMetaData の設定と、いくつかの場所で見た `

bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, instantiationType);

VS

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        string modelName = bindingContext.ModelName;
        var elementType = (int)bindingContext.ValueProvider.GetValue(string.Format("{0}.ElementType", modelName)).ConvertTo(typeof(int));
        if (elementType == 1)
        {
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => new IISElement(), typeof(IISElement));
        }
        else if (elementType == 2)
        {
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => new SharePointElement(), typeof(SharePointElement));
        }
        else if (elementType == 3)
        {
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => new SQLElement(), typeof(SQLElement));
        }
        else if (elementType == 12)
        {
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => new SharedElement(), typeof(SharedElement));
        }
        else
        {
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => new BaseProjectElement(), typeof(BaseProjectElement));
        }
        return base.BindModel(controllerContext, bindingContext);
    }
于 2014-06-09T14:35:52.057 に答える