3

TabControl現在、いくつかのを含むフォームがありますTabPage。それぞれTabPageに、検証ロジックと適切なErrorProvidersを備えたいくつかのコントロールがあります。私のOK_Button_ClickedイベントではForm.ValidateChildren()、フォームを保存して閉じるかどうかを判断するために電話をかけます。ここで、検証に失敗するコントロールがタブ1にあるが、現在表示されているタブはタブ2であるとします。ユーザーが[OK]を押すと、フォームが閉じない理由が視覚的に示されません。検証が失敗したタブに自動的に切り替えられるようにしたいので、ユーザーにErrorProviderはエラーの表示が表示されます。

Validated1つのアプローチは、すべての適切なコントロールのイベントとイベントをサブスクライブし、validating検証に失敗するたびに、それぞれがどのタブにあるかを知ることで、検証に失敗したタブのリストを作成できます。ValidationFailed私の知る限り、イベントは生成されないため、これは面倒な場合があります(たとえば、各コントロールにブール値を定義し、検証前にfalseに設定し、そのValidatedイベントでtrueに設定します)。そして、そのようなイベントがあったとしても、検証に失敗する可能性のあるコントロールごとに1つずつ、多くの検証イベントをリッスンし、コード内の未検証のタブのリストを維持することを余儀なくされます。ここで、の検証イベントに直接サブスクライブすることは機能しないことに注意する必要がありますTabPage。これは、イベント内に含まれるコントロールが検証に失敗した場合でも、検証済みとして合格するためです。

TabPage別のアプローチでは、私のコントロールがたまたまカスタムコントロールであるという事実を活用できます。次に、次のようなインターフェイスを実装させることができます。

interface ILastValidationInfoProvider
{
    public bool LastValidationSuccessful {get; set;}
}

例えば:

public MyControl : UserControl, ILastValidationInfoProvider
{
    MyControl_Validing(object sender, object sender, CancelEventArgs e)
    {
        if (this.PassesValidation())
          this.ErrorProvider.SetError(sender, null);
          LastValidationSuccessful = true;
        else
          e.Cancel = true;
          this.ErrorProvider.SetError("Validation failed!", null);
          LastValidationSuccessful = false;
    }
}

そして、呼び出し後、次のValidateChildrenようなコードを使用できます。

public void OK_Button_Click
{
     if (form.ValidateChildren())
         this.Close()
     else
         foreach (TabPage tab in this.TabControl)
             foreach (Control control in tab.Controls)
             {
                 ValidationInfo = control as ILastValidationInfoProvider
                 if (ValidationInfo != null && !ValidationInfo.LastValidationSuccessful)
                 {
                    this.TabControl.SelectTab(tab);
                    return;
                 }
             }
}

私はこのアプローチの方が好きですが、検証されるコントロールがカスタムではない場合には対応していません。

私は喜んでより良いアプローチを使用します。何か案は?

私が使用している編集Form.AutoValidate = EnableAllowFocusChange(ChrisSellsがWinFormsの本で推奨しているように)なので、検証に失敗したコントロール(他のタブへの移動を含む)からフォーカスを実際に変更できます。ErrorProviderまた、カスタムコントロールのサンプルコードを更新して、が内部に存在するという事実を強調しました。

4

1 に答える 1

3

OK、それで私はついにそれを理解しました。

キーがでTabPagesあり、値がHashSet未検証のコントロールのsである辞書を、対応するタブ内に保持します。これは、各タブのコントロールのすべての検証イベントと検証済みイベントをサブスクライブすることで簡単に実行できます。最後に、で失敗したOK_BUtton_Click場合ValidateChildren、ハッシュセットの1つが空にならず、最初の未検証のタブにジャンプします(現在選択されているタブ自体にエラーがない場合のみ)。

    Dictionary<TabPage, HashSet<Control>> _tabControls 
                           = new Dictionary<TabPage, HashSet<Control>>();

    public OptionsForm()
    {   
        InitializeComponent();
        RegisterToValidationEvents();
    }

    private void RegisterToValidationEvents()
    {
        foreach (TabPage tab in this.OptionTabs.TabPages)
        {
            var tabControlList = new HashSet<Control>();
            _tabControls[tab] = tabControlList;
            foreach (Control control in tab.Controls)
            {
                var capturedControl = control; //this is necessary
                control.Validating += (sender, e) =>
                    tabControlList.Add(capturedControl);
                control.Validated += (sender, e) =>
                    tabControlList.Remove(capturedControl);
            }
        }
    }

    private void Ok_Button_Click(object sender, EventArgs e)
    {
        if (this.ValidateChildren())
        {
            _settings.Save();
            this.Close();
        }
        else
        {
            var unvalidatedTabs = _tabControls.Where(kvp => kvp.Value.Count != 0)
                                              .Select(kvp => kvp.Key);
            TabPage firstUnvalidated = unvalidatedTabs.FirstOrDefault();
            if (firstUnvalidated != null && 
                !unvalidatedTabs.Contains(OptionTabs.SelectedTab))
                    OptionTabs.SelectedTab = firstUnvalidated;
        }
    }

かなり甘いと思います!

于 2010-02-17T23:19:28.703 に答える