1

今のところ.Net 3.5を使用しています。

現在using、コードの特定のセクションに関するイベントを無効および有効にするトリックを使用しています。ユーザーは、日、時間、分、または合計分のいずれかを変更できます。これにより、イベントの無限のカスケードが発生することはありません (たとえば、分が合計を変更する、合計が分を変更するなど)。 / より簡単な方法。どれか知っていますか?

たくましいポイントの場合:

このコントロールは複数のチームで使用されます - 恥ずかしいことはしたくありません。1 日の時間数、1 週間の日数などを定義するときに、車輪を再発明する必要はないと思います。他の標準的な .Net ライブラリにはそれが必要です。コードに関するその他のコメントはありますか? このusing (EventHacker.DisableEvents(this))ビジネス - .Net ではよくあるパターンでしょう... 一時的に設定を変更します。それの名前は何ですか?コメントで参照したり、現在の実装について詳しく調べたりしたいと思います。一般に、変更対象のハンドルだけでなく、以前の状態も記憶する必要があります (この場合、以前の状態は重要ではありません。イベントは無条件にオンまたはオフになります)。それなら可能性もあるmulti-threaded hacking. ジェネリックを利用して、間違いなくコードをきれいにすることもできます。これらすべてを理解すると、複数ページのブログ投稿につながる可能性があります。いくつかの答えを聞いてうれしいです。

PS 私は強迫性障害に苦しんでいるように見えますか? 物事を終わらせて先に進むのが好きな人もいます。私はそれらを開いたままにしておくのが好きです...常により良い方法があります。

// Corresponding Designer class is omitted.
using System;
using System.Windows.Forms;

namespace XYZ // Real name masked
{
    interface IEventHackable
    {
        void EnableEvents();
        void DisableEvents();
    }

    public partial class PollingIntervalGroupBox : GroupBox, IEventHackable
    {
        private const int DAYS_IN_WEEK      = 7;
        private const int MINUTES_IN_HOUR   = 60;
        private const int HOURS_IN_DAY      = 24;
        private const int MINUTES_IN_DAY    = MINUTES_IN_HOUR * HOURS_IN_DAY;
        private const int MAX_TOTAL_DAYS    = 100;

        private static readonly decimal MIN_TOTAL_NUM_MINUTES = 1; // Anything faster than once per minute can bog down our servers.
        private static readonly decimal MAX_TOTAL_NUM_MINUTES = (MAX_TOTAL_DAYS * MINUTES_IN_DAY) - 1; // 99 days should be plenty.
        // The value above was chosen so to not cause an overflow exception.
        // Watch out for it - numericUpDownControls each have a MaximumValue setting.

        public PollingIntervalGroupBox()
        {
            InitializeComponent();

            InitializeComponentCustom();
        }

        private void InitializeComponentCustom()
        {
            this.m_upDownDays.Maximum           = MAX_TOTAL_DAYS    - 1;
            this.m_upDownHours.Maximum          = HOURS_IN_DAY      - 1;
            this.m_upDownMinutes.Maximum        = MINUTES_IN_HOUR   - 1;
            this.m_upDownTotalMinutes.Maximum   = MAX_TOTAL_NUM_MINUTES;
            this.m_upDownTotalMinutes.Minimum   = MIN_TOTAL_NUM_MINUTES;
        }

        private void m_upDownTotalMinutes_ValueChanged(object sender, EventArgs e)
        {
            setTotalMinutes(this.m_upDownTotalMinutes.Value);
        }

        private void m_upDownDays_ValueChanged(object sender, EventArgs e)
        {
            updateTotalMinutes();
        }

        private void m_upDownHours_ValueChanged(object sender, EventArgs e)
        {
            updateTotalMinutes();
        }

        private void m_upDownMinutes_ValueChanged(object sender, EventArgs e)
        {
            updateTotalMinutes();
        }

        private void updateTotalMinutes()
        {
            this.setTotalMinutes(
                MINUTES_IN_DAY * m_upDownDays.Value + 
                MINUTES_IN_HOUR * m_upDownHours.Value + 
                m_upDownMinutes.Value);
        }

        public decimal TotalMinutes
        {
            get
            {
                return m_upDownTotalMinutes.Value;
            }
            set
            {
                m_upDownTotalMinutes.Value = value;
            }
        }

        public decimal TotalHours
        {
            set
            {
                setTotalMinutes(value * MINUTES_IN_HOUR);
            }
        }

        public decimal TotalDays
        {
            set
            {
                setTotalMinutes(value * MINUTES_IN_DAY);
            }
        }

        public decimal TotalWeeks
        {
            set
            {
                setTotalMinutes(value * DAYS_IN_WEEK * MINUTES_IN_DAY);
            }
        }

        private void setTotalMinutes(decimal nTotalMinutes)
        {
            if (nTotalMinutes < MIN_TOTAL_NUM_MINUTES)
            {
                setTotalMinutes(MIN_TOTAL_NUM_MINUTES);
                return; // Must be carefull with recursion.
            }
            if (nTotalMinutes > MAX_TOTAL_NUM_MINUTES)
            {
                setTotalMinutes(MAX_TOTAL_NUM_MINUTES);
                return; // Must be carefull with recursion.
            }
            using (EventHacker.DisableEvents(this))
            {
                // First set the total minutes
                this.m_upDownTotalMinutes.Value = nTotalMinutes;

                // Then set the rest
                this.m_upDownDays.Value = (int)(nTotalMinutes / MINUTES_IN_DAY);
                nTotalMinutes = nTotalMinutes % MINUTES_IN_DAY; // variable reuse.
                this.m_upDownHours.Value = (int)(nTotalMinutes / MINUTES_IN_HOUR);
                nTotalMinutes = nTotalMinutes % MINUTES_IN_HOUR;
                this.m_upDownMinutes.Value = nTotalMinutes;
            }
        }

        // Event magic
        public void EnableEvents()
        {
            this.m_upDownTotalMinutes.ValueChanged += this.m_upDownTotalMinutes_ValueChanged;
            this.m_upDownDays.ValueChanged += this.m_upDownDays_ValueChanged;
            this.m_upDownHours.ValueChanged += this.m_upDownHours_ValueChanged;
            this.m_upDownMinutes.ValueChanged += this.m_upDownMinutes_ValueChanged;
        }

        public void DisableEvents()
        {
            this.m_upDownTotalMinutes.ValueChanged -= this.m_upDownTotalMinutes_ValueChanged;
            this.m_upDownDays.ValueChanged -= this.m_upDownDays_ValueChanged;
            this.m_upDownHours.ValueChanged -= this.m_upDownHours_ValueChanged;
            this.m_upDownMinutes.ValueChanged -= this.m_upDownMinutes_ValueChanged;
        }

        // We give as little info as possible to the 'hacker'.
        private sealed class EventHacker : IDisposable
        {
            IEventHackable _hackableHandle;

            public static IDisposable DisableEvents(IEventHackable hackableHandle)
            {
                return new EventHacker(hackableHandle);
            }

            public EventHacker(IEventHackable hackableHandle)
            {
                this._hackableHandle = hackableHandle;
                this._hackableHandle.DisableEvents();
            }

            public void Dispose()
            {
                this._hackableHandle.EnableEvents();
            }
        }
    }
}
4

2 に答える 2

2

ブール値フィールドを使用して、setTotalMinutesメソッドが複数回実行されるのを止め、イベント ハンドラの作成をInitializeComponentCustomメソッドに移動します。

このようなもの:

public partial class PollingIntervalGroupBox : GroupBox
{
    private const int DAYS_IN_WEEK = 7;
    private const int MINUTES_IN_HOUR = 60;
    private const int HOURS_IN_DAY = 24;
    private const int MINUTES_IN_DAY = MINUTES_IN_HOUR * HOURS_IN_DAY;
    private const int MAX_TOTAL_DAYS = 100;

    private static readonly decimal MIN_TOTAL_NUM_MINUTES = 1; // Anything faster than once per minute can bog down our servers.
    private static readonly decimal MAX_TOTAL_NUM_MINUTES = (MAX_TOTAL_DAYS * MINUTES_IN_DAY) - 1; // 99 days should be plenty.
    // The value above was chosen so to not cause an overflow exception.
    // Watch out for it - numericUpDownControls each have a MaximumValue setting.
    private bool _totalMinutesChanging;

    public PollingIntervalGroupBox()
    {
        InitializeComponent();
        InitializeComponentCustom();
    }

    private void InitializeComponentCustom()
    {
        this.m_upDownDays.Maximum = MAX_TOTAL_DAYS - 1;
        this.m_upDownHours.Maximum = HOURS_IN_DAY - 1;
        this.m_upDownMinutes.Maximum = MINUTES_IN_HOUR - 1;
        this.m_upDownTotalMinutes.Maximum = MAX_TOTAL_NUM_MINUTES;
        this.m_upDownTotalMinutes.Minimum = MIN_TOTAL_NUM_MINUTES;

        this.m_upDownTotalMinutes.ValueChanged += this.m_upDownTotalMinutes_ValueChanged;
        this.m_upDownDays.ValueChanged += this.m_upDownDays_ValueChanged;
        this.m_upDownHours.ValueChanged += this.m_upDownHours_ValueChanged;
        this.m_upDownMinutes.ValueChanged += this.m_upDownMinutes_ValueChanged;
    }

    private void m_upDownTotalMinutes_ValueChanged(object sender, EventArgs e)
    {
        setTotalMinutes(this.m_upDownTotalMinutes.Value);
    }

    private void m_upDownDays_ValueChanged(object sender, EventArgs e)
    {
        updateTotalMinutes();
    }

    private void m_upDownHours_ValueChanged(object sender, EventArgs e)
    {
        updateTotalMinutes();
    }

    private void m_upDownMinutes_ValueChanged(object sender, EventArgs e)
    {
        updateTotalMinutes();
    }

    private void updateTotalMinutes()
    {
        this.setTotalMinutes(
            MINUTES_IN_DAY * m_upDownDays.Value +
            MINUTES_IN_HOUR * m_upDownHours.Value +
            m_upDownMinutes.Value);
    }

    public decimal TotalMinutes { get { return m_upDownTotalMinutes.Value; } set { m_upDownTotalMinutes.Value = value; } }

    public decimal TotalHours { set { setTotalMinutes(value * MINUTES_IN_HOUR); } }

    public decimal TotalDays { set { setTotalMinutes(value * MINUTES_IN_DAY); } }

    public decimal TotalWeeks { set { setTotalMinutes(value * DAYS_IN_WEEK * MINUTES_IN_DAY); } }

    private void setTotalMinutes(decimal totalMinutes)
    {
        if (_totalMinutesChanging) return;
        try
        {
            _totalMinutesChanging = true;
            decimal nTotalMinutes = totalMinutes;
            if (totalMinutes < MIN_TOTAL_NUM_MINUTES)
            {
                nTotalMinutes = MIN_TOTAL_NUM_MINUTES;
            }
            if (totalMinutes > MAX_TOTAL_NUM_MINUTES)
            {
                nTotalMinutes = MAX_TOTAL_NUM_MINUTES;
            }
            // First set the total minutes
            this.m_upDownTotalMinutes.Value = nTotalMinutes;

            // Then set the rest
            this.m_upDownDays.Value = (int)(nTotalMinutes / MINUTES_IN_DAY);
            nTotalMinutes = nTotalMinutes % MINUTES_IN_DAY; // variable reuse.
            this.m_upDownHours.Value = (int)(nTotalMinutes / MINUTES_IN_HOUR);
            nTotalMinutes = nTotalMinutes % MINUTES_IN_HOUR;
            this.m_upDownMinutes.Value = nTotalMinutes;
        }
        finally
        {
            _totalMinutesChanging = false;
        }
    }
}
于 2010-05-18T00:12:15.653 に答える
2

これはよく見えません。クライアント コードには、表示できないプライベート コントロールのイベントを無効にする理由がわかりません。また、パブリック プロパティが変更されたことを確認する方法もありません。パブリック プロパティの値が変更されたことを示すイベントもありません。変更イベントを無視したい場合は、単純にサブスクライブを解除するか、それらの (欠落している) イベントを無視します。

.NET Framework コントロールをガイドとして検討してください。IEventHackable に似たものはありません。

于 2010-05-18T00:57:27.663 に答える