Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / MS Press - Oop With MS Vb Net And C# Step By Step (2002)

.pdf
Скачиваний:
126
Добавлен:
12.02.2016
Размер:
2.56 Mб
Скачать

9.Click OK. The Card control icon is added to the Toolbox, as shown here.

50.Drag a card onto the form. Experiment with changing the suit and value of the card. Here’s the Jack of Diamonds:

51.The Properties window follows. Note that property descriptions are displayed at the bottom of the Properties window, and that the Card properties are shown together in the Game category of the Properties window. Also note that the Text property isn’t in the Properties window.

Creating the Deck Component

You’ll implement the Deck as a component, which means that you’ll be able to add a Deck component icon to the Toolbox. When you drag the Deck component to the form, an instance will be placed in the component tray, similar to the Timer control. By making the Deck a component, you can use the graphical tools of the Visual Studio .NET design environment to set the properties of the component.

This implementation of Deck behaves differently than the version you wrote in Chapter 4. In that version, the parameterless constructor created a 52-card deck, and a second constructor allowed you to specify the suits and face values that would appear in the deck. In this implementation, the parameterless constructor again creates a 52-card deck, but there is no constructor that takes parameters. Instead, the Deck class will support a Suits property and a FaceValues property. The user can therefore use a collection editor—similar to the collection editor for the ListBox control—to choose the values at design time. When the user changes either the Suit value or the FaceValue property, the Card instances are created to match the new values.

Add the Deck component to the project

1.Right -click the GamesLibrary project in the Solution Explorer, point to Add, and then click Add Component on the shortcut menu. The Add New Item dialog box appears.

2.Name the new component Deck.vb or Deck.cs, depending on the language you’re using.

3.Right -click in the designer and click View Code on the shortcut menu.

Examine the code for the Deck. You’ll see the important elements of a component:

§ The key feature of a component is that it can be hosted (or sited) in a container for design-time support. Thus, you’ll find this constructor:

§‘ Visual Basic

§Public Sub New(Container As System.Component Model.IContainer)

§MyClass.New()

§

§‘Required for Windows.Forms Class Compositio n Designer support

§Container.Add(me)

§End Sub

§

§// Visual C#

§public Deck(System.ComponentModel.IContainer container) {

§/// <summary>

§/// Required for Windows.Forms Class Composi tion Designer support

§/// </summary>

§container.Add(this);

§InitializeComponent();

§//

§// TODO: Add any constructor code after Initializ eComponent call

§//

}

§The second feature, also seen in the UserControl, is that the component contains a component field, so that the component can host other components:

§‘ Visual Basic

§Private components As System.ComponentModel. Container

§

§// Visual C#

private System.ComponentModel.Container components = nul l;

Define the Toolbox icon for the Deck component

To define the icon for the Deck component, add a bitmap named Deck.bmp to the project.

1.Create a 16-by-16-pixel bitmap for your project, name it Deck.bmp, and save it in the project directory. An icon is available on the companion CD in the \Chapter08 folder. The file must be named Deck.bmp.

2.In the Solution Explorer, right-click the GamesLibrary project, point to Add, and then click Add Existing Item in the shortcut menu.

3.In the Add Existing Item dialog box, change Files Of Type to Image Files.

4.Select Deck.bmp and click Open.

5.In the Solution Explorer, right-click the Deck.bmp file and click Properties on the shortcut menu.

6.In the Properties window, set the Build Action property of the bitmap file to Embedded Resource. This will cause the bitmap to be added to the

assembly file.

Add the Suits and FaceValues properties

In Chapter 4, you passed the suits and face values for the deck as parameters to the constructor. In this case, you want to allow the user to define the suits and face values after dropping the Deck component onto the form, so that the values won’t be defined when the control is created.

1.Add the following code for the Suits property. The Suits property is an array of Suit enumeration values. At design-time, the development environment will be able to examine the type of the array and provide a collection editor for entering the values. You will define the MakeDeck method in the next section. Whenever the suits in the deck are changed, a new set of cards is created.

2.‘ Visual Basic

3.Dim m_suits() As Suit = {Suit.Clubs, Suit.Diamonds, Suit.Hearts,

_

4.Suit.Spades}

5.<Category("Game"), Description("The suits in the deck.")> _

6.Public Property Suits() As Suit()

7.Get

8.Return m_suits

9.End Get

10.Set(ByVal Value As Suit())

11.m_suits = Value

12.Me.MakeDeck()

13.End Set

14.End Property

15.

16.// Visual C#

17.private Suit[] m_suits = {Suit.Clubs, Suit.Diamonds, Suit.Hearts,

18.Suit.Spades};

19.[Category("Game")]

20.[Description("The suits in the deck.")]

21.public Suit[] Suits {

22.get { return m_suits; }

23.set {

24.m_suits = value;

25.this.MakeDeck();

26.}

27.}

28.Add the following code for the FaceValues property. Like the code you added for the Suits property, this code is an array of enumeration values.

29.‘ Visual Basic

30.Dim m_faceValues() As FaceValue = {FaceValue.Ace, FaceValu e.Two, _

31.FaceValue.Three, FaceValue.Four, FaceValue.Five, FaceValu e.Six, _

32.FaceValue.Seven, FaceValue.Eight, FaceValue.Nine, FaceVal ue.Ten, _

33.FaceValue.Jack, FaceValue.Queen, FaceValue.King}

34.<Category("Game"), Description("The face values in the deck.")>

_

35.Public Property FaceValues() As FaceValue()

36.Get

37.Return m_faceValues

38.End Get

39.Set(ByVal Value As FaceValue())

40.m_faceValues = Value

41.Me.MakeDeck()

42.End Set

43. End Property

44.

45.// Visual C#

46.private FaceValue[] m_faceValues = {FaceValue.Ace, FaceValue. Two,

47.FaceValue.Three, FaceValue.Four, FaceValue.Five, FaceValu e.Six,

48.FaceValue.Seven, FaceValue.Eight, FaceValue.Nine, FaceVal ue.Ten,

49.FaceValue.Jack, FaceValue.Queen, FaceValue.King};

50.[Category("Game")]

51.[Description("The face values in the deck.")]

52.public FaceValue[] FaceValues {

53.get { return m_faceValues; }

54.set {

55.m_faceValues = value;

56.this.MakeDeck();

57.}

}

Add and modify the constructors

§Add the following call to the two existing constructors. Add this code as the last line of code in each constructor. If you’re using Visual Basic, expand the code region labeled Component Designer Generated Code to find the two constructors.

§‘ Visual Basic

§MakeDeck()

§

§// Visual C#

§MakeDeck();

Add the MakeDeck and Shuffle methods

The MakeDeck private method creates the cards using the Suits and FaceValues properties. It’s called whenever either the Suits or FaceValues property is changed.

1.Add the following code for the MakeDeck method. This is the same method you used in the Chapter 4 exercise, except that it uses the m_suits and m_faceValues fields instead of taking two parameters.

Because the deck might have cards from a previous call to MakeDeck, those cards are removed.

2.‘ Visual Basic

3.Dim m_cards As New System.Collections.ArrayList()

4.Private Sub MakeDeck()

5.‘ Dispose of the existing cards.

6.Dim count As Integer

7.For count = 0 To m_cards.Count - 1

8.CType(m_cards(count), Card).Dispose()

9.Next

10.m_cards.Clear()

11.

12.‘ Add the new cards.

13.Dim asuit, avalue As Integer

14.For asuit = 0 To suits.Length - 1

15.For avalue = 0 To m_faceValues.Length - 1

16.m_cards.Add(New Card(m_suits(asuit), m_faceValues(av

alue)))

17.Next

18.Next

19.End Sub

20.

21.// Visual C#

22.System.Collections.ArrayList m_cards = new System.Collections.

ArrayList();

23.private void MakeDeck() {

24.// Dispose of the existing cards.

25.for (int count = 0; count < m_cards.Count; count++ ) {

26.((Card)m_cards[count]).Dispose();

27.}

28.m_cards.Clear();

29.

30.// Add the new cards.

31.for (int asuit = 0; asuit < m_suits.Length; asuit++) {

32.for (int avalue = 0; avalue < m_faceValues.Length; avalue++

) {

33.m_cards.Add(new Card(m_suits[asuit], m_faceValues[ava

lue]));

34.}

35.}

36.}

The Dispose Method

The .NET runtime supports automatic garbage collection. When you create an instance of a class, a certain amount of memory is reserved for and used by the instance. At some later time in the program, you might not need that instance anymore, and you’ll want to release the memory for use by other instances in your program or other programs. The .NET runtime tracks the use of objects in your program. When the runtime determines that you have no reference variables that point to a class instance, that memory is released. One of the limitations of this garbage collection is that you can’t force memory to be released. You might want to release class instances, though, if they’re using resources that are limited, such as the number of open files. You’ll find that some objects in the .NET Framework provide a Dispose method that releases any of these resources. When you use a class that supports the Dispose method, you should call that method on any reference that you know you’re going to release. Be aware that once you call Dispose on an instance, that instance becomes invalid.

64.Add the following code for the Shuffle method. This code is unchanged from the code in Chapter 4.

65.‘ Visual Basic

66.Public Sub Shuffle()

67.Dim rgen As New System.Random()

68.Dim newdeck As New System.Collections.ArrayList()

69.While (m_cards.Count > 0)

70.‘ Choose one card at random.

71.Dim removeindex As Integer = rgen.Next(0, m_cards.Count

-1)

72.Dim removeobject As Object = m_cards(removeindex)

73.m_cards.RemoveAt(removeindex)

74.‘ Add the removed card to the new collection.

75.newdeck.Add(removeobject)

76. End While

77.

78.‘ Replace the old deck with the new deck.

79.m_cards = newdeck

80.End Sub

81.

82.// Visual C#

83.public void Shuffle() {

84.System.Random rgen = new System.Random();

85.System.Collections.ArrayList newdeck =

86.new System.Collections.ArrayList();

87.while (m_cards.Count > 0) {

88.// Remove one from m_cards.

89.int toremove = rgen.Next(0, m_cards.Count - 1);

90.Card remove = (Card)m_cards[toremove];

91.m_cards.Remove(remove);

92.// Add it to the new deck.

93.newdeck.Add(remove);

94.}

95.

96.// Replace old deck with new deck.

97.m_cards = newdeck;

}

Add the Count and indexer properties

You can now implement the Count and indexer properties, which use the ArrayList field. Again, this code is unchanged from Chapter 4, except for additions to support the Properties window.

1.Add the following code for the Count property:

2.‘ Visual Basic

3.<Category("Game"), Description(" Number of cards in the deck.")>

_

4.Public ReadOnly Property Count() As Integer

5.Get

6.Return m_cards.Count

7.End Get

8.End Property

9.

10.// Visual C#

11.[Category("Game")]

12.[Description("Number of cards in the deck.")]

13.public int Count {

14.get { return m_cards.Count; }

}

15.Add the following code for the default property in Visual Basic and the indexer property in Visual C#:

16.‘ Visual Basic

17.Default Public ReadOnly Property Cards(ByVal indexer As Intege

r)As Card

18.Get

19.If ((indexer >= 0) And (indexer < m_cards.Count)) Then

20.Return CType(m_cards(indexer), Card)

21.Else

22.Throw New ArgumentOutOfRangeException("Index out of range.")

23.End If

24.End Get

25.End Property

27.// Visual C#

28.public Card this[int indexer] {

29.get {

30.if ((indexer >= 0) && (indexer < m_cards.Count)) {

31.return((Card)m_cards[indexer]);

32.}

33.else {

34.throw new ArgumentOutOfRangeException("Index out of r

ange.");

35.}

36.}

}

37.On the Build menu, click Build Solution.

38.Refresh the GamesLibrary reference in the Memory project. Expand References under Memory in the Solution Explorer, right-click GamesLibrary and click Remove on the shortcut menu.

39.Right -click References and click Add Reference on the shortcut menu. Click Browse on the .NET tab, select the GamesLibrary.dll in the GamesLibrary\obj\

debug folder and click Open. Click OK to close the Add Reference dialog box.

Testing the Control

You can now add a Deck component to the Memory game. As with the Card control, you’ll first add the component to the Toolbox. Then all you have to do is drag it onto the form.

Add the Deck component to the Toolbox

1.Double-click Form1 in the Solution Explorer to open it in the form designer.

2.Right -click the Games tab of the Toolbox and click Customize Toolbox on the shortcut menu. The Customize Toolbox dialog box appears.

3.Click the .NET Framework Components tab and then click Browse.

4.Browse to and select the GamesLibrary.dll file, found in the obj\debug folder of the project folder. Click Open.

5.Select the Deck component in the list and click OK. The Deck component is added to the Games tab of the Toolbox.

Add a Deck component to the form

1.Drag a Deck component onto the form. An instance named Deck1 or deck1 (depending on the language you’re using) is added to the component tray of Form1.

Right -click the Deck1 control in the component tray and click Properties on the shortcut menu. Notice, in the Properties window, the Suits property of the Deck component. The ellipsis indicates that you can set the Suits array using

adesigner.

2.Explore the designer support by clicking the ellipsis button next to the Suits property. The Suit Collection Editor appears, as shown here:

77.Click Add to add a Suit value to the list.

78.Use the Value drop-down list in the Properties pane to select the Suit, as shown here:

79.After you add and delete Suit items and FaceValue items from the component, notice that the read-only Count property changes to reflect the number of Card instances in the Deck component.

Creating the Memory Control

The Memory control will use the Card control and the Deck component to implement the simple Memory game. The entire Memory game is encapsulated in the Memory control. When you assign a Deck instance to the game and call the Play method, the game is ready to run.

Add the Memory control to the project

1.Right -click the GamesLibrary project in the Solution Explorer, point to Add, and then click Add User Control on the shortcut menu. The Add New Item dialog box appears.

2.Name the new component Memory.vb or Memory.cs, depending on the language you’re using.

Define the Toolbox icon for the Memory control

To define the icon for the Memory control, add a bitmap named Memory.bmp to the project.

1.Create a 16-by-16-pixel bitmap for your project, name it Memory.bmp, and save it in the project directory. An icon is available on the companion CD in the Chapter08 folder. The file must be named Memory.bmp.

2.In the Solution Explorer, right-click the GamesLibrary project, click Add, and then click Add Existing Item in the shortcut menu.

3.In the Add Existing Item dialog box, change the Files Of Type to Image files.

4.Select the Memory.bmp file and click Open.

5.In the Solution Explorer, right-click the Memory.bmp file and click Properties on the shortcut menu.

6.In the Properties window, set the Build Action property of the bitmap file to Embedded Resource.

Add the Rows, Columns, and Deck properties

1.Edit the Memory class code by right-clicking in the designer and clicking View Code on the shortcut menu.

2.Add the following code to the Memory class for the Rows property. When the number of rows or columns changes, the control needs to be redrawn. The call to Refresh will redraw the control. The initial value is 2, which is more reasonable than the usual 0.

3.‘ Visual Basic

4.Private m_rows As Integer = 2

5.<Category("Game"), Description("Number of rows in the grid.")> _

6.Public Property Rows() As Integer

7.Get

8.Return m_rows

9.End Get

10.Set(ByVal Value As Integer)

11.If Value > 0 Then

12.m_rows = Value

13.Me.Refresh()

14.End If

15.End Set

16.End Property

17.

18.// Visual C#

19.private int m_rows = 2;

20.[Category("Game")]

21.[Description("Number of rows in the grid.")]

22.public int Rows {

23.get { return m_rows; }

24.set {

25.if (value > 0) {

26.m_rows = value;

27.this.Refresh();

28.}

29.}

}

30.Add the following code for the Columns property:

31.‘ Visual Basic

32.Private m_columns As Integer = 2

33.<Category("Game"), Description("Number of columns in the grid." )> _

34.Public Property Columns() As Integer