Visual Studioの文句:警告1デザイナーはタイプ 'RentalEase.CustomBindingNavForm'のインスタンスを作成する必要がありますが、タイプが抽象として宣言されているため作成できません。
Visual Studioでは、フォームのデザイナーにアクセスできません。このクラスは、CustomBindingNavFormのすべての抽象メソッドをすでに実装しています。 CustomBindingNavFormは、具体的で抽象的な関数をいくつか提供します。
これを回避する方法はありますか?
クラスは次のとおりです。
public abstract class CustomBindingNavForm : SingleInstanceForm {
//Flags for managing BindingSource
protected bool isNew = false;
protected bool isUpdating = false;
/// <summary>
/// This is so that when a new item is added, it sets isNew and firstPass to true. The Position Changed Event will look for
/// firstPass and if it is true set it to false. Then on the next pass, it will see it's false and set isNew to false.
/// This is needed because the Position Changed Event will fire when a new item is added.
/// </summary>
protected bool firstPass = false;
protected abstract bool validateInput();
protected abstract void saveToDatabase();
//manipulating binding
protected abstract void bindingSourceCancelResetCurrent();
protected abstract void bindingSourceRemoveCurrent();
protected abstract void bindingSourceMoveFirst();
protected abstract void bindingSourceMoveNext();
protected abstract void bindingSourceMoveLast();
protected abstract void bindingSourceMovePrevious();
protected abstract void bindingSourceAddNew();
public void bindingNavigatorMovePreviousItem_Click(object sender, EventArgs e) {
if (validateInput()) {
bindingSourceMovePrevious();
} else {
DialogResult cont = MessageBox.Show(null, "There are errors in your data. Click Cancel to go back and fix them, or ok to continue. If you continue, changes will not be saved.", "Continue?", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (cont == DialogResult.OK) {
if (isNew) {
bindingSourceRemoveCurrent();
isNew = false;
} else {
bindingSourceCancelResetCurrent();
bindingSourceMovePrevious();
}
}
}
}
public void bindingNavigatorAddNewItem_Click(object sender, EventArgs e) {
if (validateInput()) {
saveToDatabase();
bool temp = isUpdating;
isUpdating = true;
bindingSourceAddNew();
isUpdating = temp;
isNew = true;
firstPass = true;
} else {
DialogResult cont = MessageBox.Show(null, "There are errors in your data. Click Cancel to go back and fix them, or ok to continue. If you continue, changes will not be saved.", "Continue?", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (cont == DialogResult.OK) {
if (isNew) {
bindingSourceRemoveCurrent();
isNew = false;
} else {
bindingSourceCancelResetCurrent();
}
bool temp = isUpdating;
isUpdating = true;
bindingSourceAddNew();
isUpdating = temp;
isNew = true;
firstPass = true;
}
}
}
public void bindingNavigatorMoveFirstItem_Click(object sender, EventArgs e) {
if (validateInput()) {
bindingSourceMoveFirst();
} else {
DialogResult cont = MessageBox.Show(null, "There are errors in your data. Click Cancel to go back and fix them, or ok to continue. If you continue, changes will not be saved.", "Continue?", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (cont == DialogResult.OK) {
if (isNew) {
bindingSourceRemoveCurrent();
isNew = false;
} else {
bindingSourceCancelResetCurrent();
}
bindingSourceMoveFirst();
}
}
}
public void bindingNavigatorMoveNextItem_Click(object sender, EventArgs e) {
if (validateInput()) {
bindingSourceMoveNext();
} else {
DialogResult cont = MessageBox.Show(null, "There are errors in your data. Click Cancel to go back and fix them, or ok to continue. If you continue, changes will not be saved.", "Continue?", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (cont == DialogResult.OK) {
if (isNew) {
bindingSourceRemoveCurrent();
isNew = false;
} else {
bindingSourceCancelResetCurrent();
}
bindingSourceMoveNext();
}
}
}
}
アーバンポテト(ダウン)のコンテンツは見たことがありませんが、私と Smelch が解決策を思いつきました。 Form
自体は抽象クラスを継承しているので、彼らが教えてくれないのはそれだけです抽象化できない第1レベルの継承、第2レベルの継承は可能です。
そこからは、真ん中に空のクラスを置き、フォーム宣言の周りに#if debug
をラップするだけで、準備は完了です。必ずリリースモードでリリースし、デバッグモードで設計してください(これは非常に一般的です)。
設計(デバッグ)およびビルド(リリース)時に、完全な設計者サポートと実際の抽象基本クラスを取得できます。これは、そのたびに抽象基本クラスが使用されるためです。
これは、UserControlを継承する抽象クラスで機能しました
public class AbstractCommunicatorProvider : TypeDescriptionProvider
{
public AbstractCommunicatorProvider(): base(TypeDescriptor.GetProvider(typeof(UserControl)))
{
}
public override Type GetReflectionType(Type objectType, object instance)
{
return typeof(UserControl);
}
public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
{
objectType = typeof(UserControl);
return base.CreateInstance(provider, objectType, argTypes, args);
}
}
[TypeDescriptionProvider(typeof(AbstractCommunicatorProvider))]
public abstract partial class SelectorBase : UserControl
{
///class contents
}
これをすべての派生クラスに追加する必要はありませんでしたが、状況によっては追加する必要があるかもしれません。
次のような抽象クラスの属性を使用してこれを解決できます
[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider<MyBaseFormEf, Form>))]
これは、必要なすべての場合に機能します。 AbstractControlDescriptionProviderは以下のとおりです
public class AbstractControlDescriptionProvider<TAbstract, TBase> : TypeDescriptionProvider
{
public AbstractControlDescriptionProvider()
: base(TypeDescriptor.GetProvider(typeof(TAbstract)))
{
}
public override Type GetReflectionType(Type objectType, object instance)
{
if (objectType == typeof(TAbstract))
return typeof(TBase);
return base.GetReflectionType(objectType, instance);
}
public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
{
if (objectType == typeof(TAbstract))
objectType = typeof(TBase);
return base.CreateInstance(provider, objectType, argTypes, args);
}
}