|
That's not quite true. You can use the Grid layout in WinForms as you can host WPF content in a WinForm. Whether you'd want to is a different matter.
|
|
|
|
|
I didn't know that! Any links to how? (Not that I want to do it, it would just be for reference)
Ideological Purity is no substitute for being able to stick your thumb down a pipe to stop the water
|
|
|
|
|
You just need to use an ElementHost object. It's under the WPF tab.
|
|
|
|
|
cheers!
Ideological Purity is no substitute for being able to stick your thumb down a pipe to stop the water
|
|
|
|
|
Take a look at this[^]
I have added WPF stuff to a winform, just for fun. I don't do it for real programs.
Just because the code works, it doesn't mean that it is good code.
|
|
|
|
|
Background:
My lady loves the game of Keno, specifically Cleopatra Keno. Her birthday is in 4 weeks, and I have 3 weeks relatively free until classes start again. I'd like to make a Windows version of the game for her to play at home for her birthday. Not only would she love it, but it would save me a ton of money if I could get her used to playing at home instead of a casino. The logic of the game is trivial. The player selects 3 to 10 numbers from a field of 80, places a bet, and presses Go to run a game.In Cleopatra Keno, if the run is a winner, and the last number drawn is one selected by the player, the game awards 12 free runs with doubled payouts. Each run draws 20 numbers from the field. The overall payout is only 90.1%, so it's a lousy money maker, but I have to admit that it's fun when a game starts hitting these bonus rounds over and over... it does happen.
So, I've created a Keno tile class as a user control. It has a button overlaid on a UserControl background with a Text member that represents the number of the tile, set in the constructor for each instance. A Tile contains methods to set and reset states of Selected by the player, Hit during game play, Last hit in a run, et cetera. These are all self-contained functions to control the colors displayed to the user. But how do I lay them out in a rectangular grid, and what's the best way to handle interactions between the game and the user? I think that having the individual tiles raise an event when the user makes a change makes sense, but during the game run, what should control?
The layout question is really the top priority right now. I have to instantiate 80 separate controls and make them display in a grid of 8 rows of 10 columns, and I'm not sure of the most efficient way to accomplish that. I could calculate the XY coordinates for each top left corner and render them that way, but that seems awfully ugly. Is there a better way?
Will Rogers never met me.
|
|
|
|
|
Sorry mate, but that sounds a horrible way to layout the interface. If I were doing this, I would consider drawing the grid out in it's entirety. I would then have a class which represented a single tile, which would contain a Rectangle that represents the tile location on the screen.
I would have a TileContainer class which was responsible for maintaining the collection of tiles and performing operations such as getting the "hit" tile. As a hint, a simple method would be to just iterate through the tiles performing a Rectangle.Contains to see which rectangle contains the point - there are other optimisations you could perform, but on 80 items, this wouldn't be an expensive operation.
|
|
|
|
|
I'll rethink it, but I was really hoping to avoid all the graphics details. The UI crap wastes 95% of my time as it is, and I hate it. I was hoping that using controls I could get around that stuff.
Will Rogers never met me.
|
|
|
|
|
With my solution all you do is draw the lines and draw the text. Heck, you even have the coordinates worked out for you in each tile.
|
|
|
|
|
I definitely think your suggestion is the best suggestion so far!
I do something similar with my webcam security software where there are N webcams.
So I have what I call a rig that contains a collection of cameras.
The numbers of tiles and their row or column is not relevant to the design of the tile as each tile can keep track of it's own position.
If you want to know what is at a particular positiion all you have to do is ask for the tile at that postion - there could be a method such as Rectangle(x,y) within the container class.
“That which can be asserted without evidence, can be dismissed without evidence.”
― Christopher Hitchens
|
|
|
|
|
GuyThiebaut wrote: If you want to know what is at a particular positiion all you have to do is ask
for the tile at that postion - there could be a method such as
Rectangle(x,y) within the container class.
Excellent suggestion.
|
|
|
|
|
Roger Wright wrote: I could calculate the XY coordinates for each top left corner
That's how I'd do it. :shrug: But I'm not much good with graphics, so controls are my hammer of choice when I see that kind of nail.
However, won't you allow the user to select sub-groups of numbers? In a "real" game that's done with drawing circles around some of the numbers -- so you may need to use graphics anyway. Or some sort of shift-clicking combined with some visual indication -- or kind of like grouping objects in Visio.
P.S. Or use a DataGridView?
modified 18-May-12 11:51am.
|
|
|
|
|
PIEBALDconsult wrote: won't you allow the user to select sub-groups of numbers?
Of course, by clicking each control. There's no need to have them grouped in any special way. On the real game, you select tiles by poking the screen with a finger; this will just use the mouse.
I've never used a DataGridView before, and don't know if I can stuff a control into one. I'll give it a try!
Will Rogers never met me.
|
|
|
|
|
I'm not sure you understood. Say the user selects { 1 , 2 , 3 , 4 , 5 , 6 } as the main group -- he can also select sub-groups { 1 , 2 , 3 } and { 4 , 5 , 6 } for example.
|
|
|
|
|
Oh! I see. Yes, there are games where this is done, but not on Cleopatra Keno.
Will Rogers never met me.
|
|
|
|
|
Ah. So why play it then? Doesn't it waste paper?
|
|
|
|
|
No, but it does sometimes waste an awful lot of quarters!
Will Rogers never met me.
|
|
|
|
|
Whenever I get into graphics with windows, the actual math way always trumps the user control way, every time. Windows forms and WPF just don't like a lot of controls. On the plus side once you have done the math a few times it really isn't so hard.
|
|
|
|
|
I'm going for a WPF solution. I've never tried it, so it should be an adventure. To start, I'm trying a grid within a grid - the outer for the overall game layout, and the inner for the array of Keno tiles. This should be an interesting adventure...
Will Rogers never met me.
|
|
|
|
|
Hi Roger,
I'm into nested UserControls. I'll assume that what I say here is easily "tranposed" from WinForms to WPF, while being not entirely sure that's true.
The case of 90 UserControls (80 tile controls, and, in this case, ten "row of tiles" containers) would not worry me the least bit in terms of performance ... in WinForms.
I'd start with your basic Usercontrol, 'TheTile,' and make it expose public properties such as its (invariant) unique number, a boolean for its current "state:" selected or unselected.
Inside TheTile, I'd use a a Label control, rather than a button, which would contain the number, and I'd create Public get/set properties to set the number.
I'd then build a 'RowOfTiles' UserControl each of which would contain ten instances of the 'TheTile:' in the 'Load event of RowOfTiles, and add them to the RowOfTiles instance Control Collection: by setting the Dock property of TheTile to Dock.Right, you get automatic proper horizontal alignment/order.
Then in the Form/Window Load event, I'd for-loop instantiate ten instances of the RowOfTiles control, and add them to the Control collection of the Panel container on the Form. Again, using Dock set to Dock.Bottom will give you automatic proper vertical alignment/order.
On a "global level" I'd create a collection of type TheTile to hold the currently selected tiles. Something like: List<TheTile>.
And I'd create a master collection of the form:
List<RowOfTiles> to facilitate rapid enumeration of the whole collection and manipulation of it. Or maybe just a "flat list" of type List<TheTile> to hold all the Tiles.
It took me less than ten minutes to implement a simple working prototype of this grid of "nested" UserControls in WinForms, all properly labeled from #1~80, and which switched tile colors (switched the background color of the Label enclosed in the TheTile UserControl) as clikcing (the Label)toggled TheTile between 'Selected and 'Unselected states, and updated the master (global static, on the Main Form) collection of "SelectedTiles."
Screen shot here:[^]
While I could not find any clear description of "Cleopatra Keno" on the web, I was baffled enough reading the WikiP entry on Keno itself
What really puzzles me in your description of Cleopatra flavor Keno is the implication that the user can do something while the game is in progress, if I interpret what you say in the words: "Hit during game play" correctly, but, please, don't feel you need to educate me on this, because I guarantee you I'll never play Keno : I gamble with my life everyday riding a bicycle in the northern Thailand anarchy known as "traffic," actually a major form of birth control, as well as a major factor in culling out the wick and sick from the population
Thanks for the impetus to actually write some code for the first time in three months !
best, Bill
p.s. pm me if you want the source for the C# WinForms quick prototype.
"Humans are amphibians ... half spirit and half animal ... as spirits they belong to the eternal world, but as animals they inhabit time. This means that while their spirit can be directed to an eternal object, their bodies, passions, and imaginations are in continual change, for to be in time, means to change. Their nearest approach to constancy, therefore, is undulation: the repeated return to a level from which they repeatedly fall back, a series of troughs and peaks.” C.S. Lewis
|
|
|
|
|
That looks slick, Bill. What you describe is generally what I started out doing. I used the layered approach in order to control color without having to mess with Paint functions. In the game, the tile center, which I represented as a button, has a medium blue color, while the text and outer border are light blue. When, before the start of a game, the player selects his numbers, the border and text change to yellow. During the play, each time the game selects a number, the center turns from medium blue to red. I can change the control main background color easily to control the border color, the backcolor property of the button to change the center color, and the foreground color of the button to change the text color. The button gives me an event that I can use to set the selected status of the player's choices. I planned to use this event to fill an array representing the selected numbers, and a random number generator to set the game's choices, then compare the arrays to determine the payoff, if any.
I was dismayed to learn from others that so many controls causes problems. It's a relief to hear from you that this isn't necessarily true. On the other hand, this caused me to look into WPF, and though I have no interest in learning XAML, the graceful way in which this framework handles events is very attractive!
Keno, by the way, is a game of pure chance. You pick numbers and hope that the machine will pick the same ones. It's logically identical with any state lottery, except that in Cleopatra Keno, the payout is 90.1% of the amount paid in; no state lottery comes close. It's fun if a particular game likes the same number you do on the night you're playing it, boring as watching paint dry if it doesn't. I much prefer Poker, since there is a chance to change the outcome by discarding some cards and drawing replacements, but as in any casino game, it is as likely to stick a hose in your pocket and suck until all it gets is lint, as it is to pay off big wins. I had a dreadful night playing Keno last Friday - nothing hit for me. But when I changed to Poker, I was $2000 ahead in a couple of hours, playing $1.25 a hand. Of course, when I went back to Poker the next day (there's not much else to do when you're staying in a hotel/casino) the Poker machines slowly took back all they'd granted me the night before, and the Keno games still hated me. Over the entire weekend, I broke even, paying for the room and meals with winnings. A free vacation is not to be scorned...
Maybe I'll pursue both approaches, just to see which turns out to be simpler. In fact, if I can find the time, a side-by-side comparison of developing the same program in WinForms and WPF might make an interesting article.
Will Rogers never met me.
|
|
|
|
|
Hi Roger,
I think I'll play with this a bit more starting with:
1. add a field at the top of the UI to show the number of Tiles selected by the player. Perhaps the user should be allowed/required to enter the number prior to play ?
2. add a "play" button (initially disabled) to trigger the game
3. "enforce" minimal selection, or prevent too many tiles being selected than the game permits: before the Play button is enabled.
4. After the "run of the game:" those tiles selected by the random number generator will have the BackColor of TheTile set to Red: that will mean the tiles selected, by the player, before the game that are "winners," will have the orange background (indicating selected) for their internal TextBox surrounded by TheTile BackColor set to Red.
5. I might implement a global enumeration for each instance of TheTile; something like:
0 unselected and not a winner
1 unselected and a winner
2 selected and not a winner
3 selected and a winner
However, if I maintain generic List collections of selected tiles, and, after the game run, a generic list of winner tiles: calculating matches is trivial, so: maybe a enumeration is not really necessary.
I'd have to do some research to figure out the algorithm for the "payout," and implement the "additional bonus runs" ... triggered when the last number selected by the player is a "winner" feature ... if I understand you correctly.
Is this "cycle of additional bonus runs" always going to use the same original tiles selected by the player, or does the player have the opportunity to change the selection before each "bonus run" ?
My guess would be that it would re-use the original numbers, and the "bonus runs" are done automatically ... with the pay-out calculated on after each run and added to the original pay-out ?
Maybe this exercise will help me get over my complete disgust with the apparent future of what I call "Windows 8 Bi-Polar," and its freak-show collage of XAML, WRT, Metro, and the "Classic Desktop" (not to mention what will happen if you want to program on ARM-driven hardware) ?
best, Bill
"Humans are amphibians ... half spirit and half animal ... as spirits they belong to the eternal world, but as animals they inhabit time. This means that while their spirit can be directed to an eternal object, their bodies, passions, and imaginations are in continual change, for to be in time, means to change. Their nearest approach to constancy, therefore, is undulation: the repeated return to a level from which they repeatedly fall back, a series of troughs and peaks.” C.S. Lewis
|
|
|
|
|
Hi Roger,
This is getting to be fun[^], and I thank you for that !
best, Bill
"Humans are amphibians ... half spirit and half animal ... as spirits they belong to the eternal world, but as animals they inhabit time. This means that while their spirit can be directed to an eternal object, their bodies, passions, and imaginations are in continual change, for to be in time, means to change. Their nearest approach to constancy, therefore, is undulation: the repeated return to a level from which they repeatedly fall back, a series of troughs and peaks.” C.S. Lewis
|
|
|
|
|
That's looking great, Bill!
Have you run into any performance/reliability problems yet? Sadly, I haven't had a chance to open VS in a week, things have been so ridiculously busy around here. It's a good thing that I don't make my living doing this, but it would be really nice to have the time to enjoy my hobby once in a while. Oh well, I have a 3-day weekend coming up, and maybe I'll get some time to play then.
Will Rogers never met me.
|
|
|
|
|
If you are going the WPF route, I would use a UniformGrid to layout your "tiles"; I use it anytime that I need to compose UI's with many similar controls and groupings (usually on-the-fly).
Here's a code-only example that doesn't require XAML source code:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace CodeOnlyWPF {
class Program {
[STAThread]
static void Main( string[] args ) {
Window window = new Window() {
WindowStartupLocation = WindowStartupLocation.CenterScreen,
SizeToContent = SizeToContent.WidthAndHeight
};
UniformGrid ug = new UniformGrid() {
Columns = 10,
Rows = 8
};
for ( int i = 1; i <= 80; i++ ) {
Button btn = new Button() {
Content = i.ToString(),
Width = 40,
Height = 40,
Background = Brushes.GhostWhite
};
btn.Click += new RoutedEventHandler( btn_Click );
ug.Children.Add( btn );
}
window.Content = ug;
Application app = new Application();
app.Run( window );
}
static void btn_Click( object sender, RoutedEventArgs e ) {
Button btn = sender as Button;
if ( btn.Tag == null ) {
btn.Background = Brushes.Gold;
btn.Tag = true;
}
else {
btn.Background = Brushes.GhostWhite;
btn.Tag = null;
}
}
}
}
|
|
|
|
|