簡體   English   中英

為什么/如何使我能夠在Calendar控件中選擇多天?

[英]Why/how does this enable me to select multiple days in a Calendar control?

我在想着Calendar.SelectedDates是只讀的事實。 我想要一種以編程方式在日歷中選擇多個日期的方法。 我找到了下面的代碼片段,這些片段完全符合我的要求,但是我不明白它為什么起作用:

protected void Page_Load(object sender, EventArgs e)
{
    SelectedDatesCollection dates = Calendar1.SelectedDates;
    dates.Add(new DateTime(2012, 5, 1));
    dates.Add(new DateTime(2012, 5, 5));
    dates.Add(new DateTime(2012, 5, 9));
}

我所期望的(鑒於我對C#的了解有限)完全相反:

protected void Page_Load(object sender, EventArgs e)
{
    ArrayList datelist = new ArrayList();
    datelist.Add(new DateTime(2012, 5, 1));
    datelist.Add(new DateTime(2012, 5, 5));
    datelist.Add(new DateTime(2012, 5, 9));
    Calendar1.SelectedDates = new SelectedDatesCollection(datelist);
}

SelectedDates只讀屬性如何受本地SelectedDatesCollection變量影響? 為什么添加到該局部變量會影響Calendar1.SelectedDates屬性?

(這只是拖放式ASP.Net日歷,沒有更改/特殊屬性)

SelectedDatesCollection作為屬性是ReadOnly,但是您仍然可以將其更改為對象,如添加或刪除項。

更改對象(也稱為更改數據的方法來調用它的方法)與更改對象引用本身(作為類的成員等)之間是有區別的。

通過做:

SelectedDatesCollection dates = Calendar1.SelectedDates;

您不是在復制集合,而只是保存它的引用,就像給它起另一個名字一樣。

最終,您還可以執行以下操作:

protected void Page_Load(object sender, EventArgs e)
{
    Calendar1.SelectedDates.Add(new DateTime(2012, 5, 1));
    Calendar1.SelectedDates.Add(new DateTime(2012, 5, 5));
    Calendar1.SelectedDates.Add(new DateTime(2012, 5, 9));
}

只是有人會說另一種方式更具可讀性。

datesCalendar1.SelectedDates包含對完全相同的對象的引用。 dates上調用Add方法就像在Calendar1.SelectedDates上調用一樣,反之亦然。

如您所說,您無法在第二段代碼中嘗試重新分配Calendar1.SelectedDates的原因(未編譯)是因為SelectedDates被標記為只讀。

將成員標記為只讀僅意味着它僅會立即分配或在class / struct / etc的構造函數中分配。

但是,這並不意味着您不能在該對象內更改數據。

從現在開始,這只是一些額外的信息

有一個類ReadOnlyCollection,不允許更改其ELEMENTS。

因此,例如,擁有一個只讀的ReadOnlyCollection意味着您不能更改成員,也不能更改元素。

例子:

public class Class1
{
    public List<int> Numbers = new List<int> {1, 2, 3};
}

public class Class2
{
    public readonly List<int> Numbers = new List<int> {1, 2, 3};
}

public class Class3
{
    public ReadOnlyCollection<int> Numbers = new ReadOnlyCollection<int> {1, 2, 3};
}

public class Class3
{
    public readonly ReadOnlyCollection<int> Numbers = new ReadOnlyCollection<int> {1, 2, 3};
}

差異:

var c1 = new Class1();
var c2 = new Class2();
var c3 = new Class3();
var c4 = new Class4();

c1.Numbers = new List<int> {4, 5, 6}; // Works
c1.Numbers.Clear(); // Works

c2.Numbers = new List<int> {4, 5, 6}; // Error
c2.Numbers = c2.Numbers; // Error - you just can't reassign it!
c2.Numbers.Clear(); // Works - you are just calling the Clear method of the existing list object.

c3.Numbers = new ReadOnlyCollection<int> {4, 5, 6}; // Works - the member is not readonly

// ReadOnlyCollection doesn't allow to change it's elements after initializing it.
// It doesn't even have these functions:
c3.Numbers.Clear(); // Error
c3.Numbers.Add(); // Error
c3.Numbers.Remove(2); // Error

c4.Numbers = new ReadOnlyCollection<int> {4, 5, 6}; // Error - the member is marked as readonly

// ReadOnlyCollection doesn't allow to change it's elements after initializing it.
// It doesn't even have these functions:
c4.Numbers.Clear(); // Error
c4.Numbers.Add(); // Error
c4.Numbers.Remove(2); // Error

請嘗試以下操作-請記住,他們還必須能夠取消選擇日期:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (ViewState["StartDates"] == null)
        {
            startDates = new ArrayList();
        }
        else
        {
            startDates = ViewState["StartDates"] as ArrayList;
        }
    } 

    protected void StartSelection_Changed(Object sender, EventArgs e)
    {
        startCalendar.SelectedDate = new DateTime(startCalendar.SelectedDate.Year,
            startCalendar.SelectedDate.Month, startCalendar.SelectedDate.Day, 0, 0, 0);

        // c.f. http://www.mikepope.com/blog/AddComment.aspx?blogid=604
        int index = -1;
        index = startDates.IndexOf(startCalendar.SelectedDate);
        if (index >= 0)
        {  
            startDates.RemoveAt(index);
        }
        else
        {
            DateTime dateTime 
                = new DateTime(startCalendar.SelectedDate.Year,
                    startCalendar.SelectedDate.Month, 
                        startCalendar.SelectedDate.Day, 0, 0, 0);

            startDates.Add(dateTime);
        }

        ViewState["StartDates"] = startDates;
        DisplaySelectedDates();
    }


    protected void DisplaySelectedDates()
    {
        startCalendar.SelectedDates.Clear();
        for (int i = 0; i < startDates.Count; i++)
        {
            startCalendar.SelectedDates.Add((DateTime)startDates[i]);
        }
    }

您的問題有一個更簡潔的答案:

SelectedDates只讀屬性如何受本地SelectedDatesCollection變量影響? 為什么添加到該局部變量會影響Calendar1.SelectedDates屬性?

SelectedDatesCollection是引用類型; 只讀SelectedDates屬性返回對該類型對象的引用 因此,局部變量還保存對該對象的引用 由於該對象與CalendarControl引用的對象相同,因此對該對象的更改將反映在CalendarControl中。


由這種情況引起的另一個問題:

在設計課程時會引起問題嗎?

是! 許多開發人員由於錯誤的假設而被誤認為是安全的,這種錯誤的假設是,例如,通過只讀屬性公開列表將阻止使用者代碼修改列表。 這當然是不正確的: 通過只讀屬性公開私有引用類型的數據允許代碼的用戶更改對象。 例如:

class Parent
{
    private readonly List<Child> _children = new List<Child>();
    public List<Child> Children { get { return _children; } }
}

class SomeOtherClass
{
    void EvilParentConsumer()
    {
        Parent a = GetSomeParent();
        Parent b = GetSomeParent();

        //Kidnap all of b's children and give them to a!!!
        a.Children.AddRange(b.Children);
        b.Children.Clear();
    }
}

正如Yorye Nathan所指出的,您可以通過將私有列表作為ReadOnlyCollection公開來防止這種情況。 如果您的要求允許,另一種實現方法是將集合公開為IEnumerable<T> ,而該公開不公開向集合添加元素的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM