I've been busy working on a program that can solve Minesweeper puzzles (for no other reason than I think it's fun). When it comes down to the UI, though, I greatly dislike the idea of instantiating over a hundred of the same control, one per cell. Should I create a custom control that handles all of its drawing and input itself? What approach do you guys suggest?
I'm using WPF, and I'm pretty new. Any pointers would be awesome.
Yes a custom control would be a good idea. Also, M-V-VM is a must in a situation like this; it will reduce the complexity of your app greatly.
I'd take a UniformGrid and use Buttons as the squares. You'd have to create a tri-state custom button if you want to add in the "?" intermediate state.
The model for the button would look like
public class MineSquare : INotifyPropertyChanged
{
// exploded, number, or nothing
pubic ImageSource ButtonImage {get;private set;}
// true, then goes to false when clicked
public bool CanClick {get; private set;}
// bound to the Command of the button
public ICommand Click {get; private set;}
}
You deal with the model in code rather than the controls. Drop in nine MineSquares into an ObservableCollection on your ViewModel bound to your UniformGrid and you have a 3x3 minesweeper game. Each button handles its own logic. You can hook into the models via the view model to iterate over all squares and determine if everybody has been clicked.
I think you should create a single, owner-drawn control. WPF is cool, but a WPF app still has the same limitations regarding the total number of controls on a form, so having a separate control for each cell in Minesweeper would still be problematic.
Minesweeper is pretty played out, though, as much as I love it myself. Maybe you could have more fun with it by making the cells hexagonal instead of rectangular, and arranging the mines so that they spell out dirty words or something.
Related
When creating a WatchKit (WatchOS) Interface controller in the storyboard designer/editor, I cannot set it's class to something that is not itself type WKInterfaceController nor an immediate derived child of WKInterfaceController.
Basically in the hope of abstraction and better code reuse, better design overall, I would like to be able to use classes that are how to say, a more distant relative of their base WKInterfaceController
Basically right now it seems that your stuck using the storyboard designer to make a new WatchOS project. And using the storyboard designer you only have the option to select the WKInterfaceController class:
public partial class WKInterfaceController
or one that directly inherits from it:
public partial class ChildInterfaceController : WKInterfaceController
but nothing else such as:
public partial class GrandChildInterfaceController: ChildInterfaceController
So is there any way to do this that doesn't risk the chance of getting corrupted when you reenter the storyboard designer at some point?
Note: I've already asked if it is possible to avoid using a storyboard all together, but that has gone unanswered so I'm assuming no.
For clarity I'm talking about this dialog for "class":
Image below is what iv constructed already, but can see the daunting task of creating it for 40 students with 250-300 entires each...What layout would i use if i was to display over 10000 textviews(strings)?
Think of it as a table where there are 40 student names down the side of the xml layout and each of these students had its own row. In that row it displayed them being absent or present with the letter A(Absent) and P(Present).
I need each student to have at least 250 entries or textviews for the school calandar year. So as you can see 250 entries multiplied by 40 students equals alot of individual textviews which is not ideal.
I am stuck on which layout to use; ListView, GridView or is there another easier layout to display all this data that is being passed from another class using the spinners of each student? So every time a user pushes the confirm button from the class with the spinners it will take that string and pass onto the class that i want to display it. Like a roll book for school. Thanks
Forget layouts here. Better draw everything completely on your own. It may be a bit more work, but you have complete control over what's going on, you don't need any XML, and you avoid surprises with the sometimes funny, sparsely documented behavior of those layouts. As a start, you create your own View class and implement a few functions:
public class UiView extends View {
#Override
protected void onDraw(Canvas canvas) {/*...*/}
#Override
public boolean onTouchEvent(MotionEvent event) {/*...*/}
}
and put it into your main layout:
<com.mytool.UiView ...
Then you have complete freedom to tune the behavior by implementing onDraw and onTouchEvent.
I have a UISplitViewController which has a UINavigationController in the master and a UIViewController in the detail. When the device is orientated into landscape mode I want the normal behaviour to be preserved. I.e. The master gets shown in landscape and hidden in portrait.
However depending what the user clicks in the master depends on which UIViewController is loaded into the detail part of the UISplitViewController. What I would like is for the master to be hidden in landscape mode when a user clicks on a button in the detail UIViewController. The problem is I can't get this to work.
My delegate looks like this (have removed some lines for simpler viewing):
public class SplitControllerDelegate : UISplitViewControllerDelegate {
SplitViewController incomingController;
private bool hideMaster = false;
public override bool ShouldHideViewController (UISplitViewController svc,
UIViewController viewController,
UIInterfaceOrientation inOrientation) {
return hideMaster;
}
public void SetHideMaster(bool value) {
hideMaster = value;
}
}
I then call it from the detail UIViewController like
splitControllerDelegate.SetHideMaster(value);
However nothing changes. I'm unsure of how to make it perform the change? Should the master disappear immediately? What causes the WillHideViewController to fire?
Thanks
Mike
What you're trying to do cannot be done officially. ShouldHideViewController() is called only upon device rotation. So unless you rotate forth and back, your controller won't disappear.
You have various options:
Don't use UIListViewController but some other third party replacement
Use UIViewController containment feature of iOS5 and implement your own split view
Apply a hack to UISplitViewController
About the last point. You should be able to force ShouldHideViewController() being called if you set the Delegate property to NULL and then assign a new delegate. Afterwards, call the WillRotate() method of the split view controller using the current orientation.
I'd go for the 2nd option.
By design you cannot do much with the standard UISplitView, try that third party control :
https://github.com/mattgemmell/MGSplitViewController
I am developing a control for an IPAD application (My first time doing Apple development). Its a simple control that mimics a grid - consists of a collection of UIViews (each of which represents a cell) all added to a parent UIView (in a grid like fashion).
One of the requirements is to implement a swipe gesture - the users swipe across the grid to activate/inactivate the cell - this corresponds to a 1/0 in the database.
I create a UISwipeGesture and added it to each of my UIView which represents a cell. That appears to be an incorrect approach as it fires the event for the UIView in which the swipe originated but not across all the UIViews.
My understanding would be that i need to implement the SwipeGesture across the parent UIView which contains all these children UIView. However if i do that how will i know which child UIView has been swiped over? Or any other approach which would make sense?
I know this thread is fairly old, but I created a Swipe extension method that might have helped.
View.Swipe(UISwipeGestureRecognizerDirection.Right).Event += Swipe_Event;
void Swipe_Event(ViewExtensions.SwipeClass sender, UISwipeGestureRecognizer recognizer)
{
View view = sender.View; // do something with view that was swiped.
}
This may not answer your question, but I can speak to the approach I've taken here with a similar use case:
1) I would abandon UIScrollView and use UITableView. You'll notice that UITableView inherits from UIScrollView and has all the performance benefits of virtualization and cell / view re-use. Which you'll find terribly useful as you work towards optimizing your app for performance on device.
2) Utilize the UITableViewCell's ContentView to create custom "Grid" cells. Or better yet, utilize MonoTouch.Dialog if you're not required to create Grid rows ad-hoc.
3) Use this awesome class (props to #praeclarum) to setup gestures in MonoTouch. You essentially provide a UIGestureRecognizer as a generic argument. You can then utilize the LocationInView method to grab the point in the UITableView where the gesture occurred
public void HandleSwipe(UISwipeGestureRecognizer recognizer)
{
if(recognizer.State == UIGestureRecognizerState.Ended) {
var point = recognizer.LocationInView(myTableView);
var indexPath = myTableView.IndexPathForRowAtPoint(point);
// do associated calculations here
}
}
I think you're correct that the gesture recognizer has to be attached to the parent view. In the action method associated with the gesture recognizer I think you can use the Monotouch equivalent of CGRectContainsPoint() to determine whether the swipe occurred in a particular subview. I imagine you would have to iterate through the subviews until you found the one in which the swipe occurred. I'm not aware of a method that would immediately identify the swiped subview.
my question is about view controllers, delegates and all that in general. I feel perfectly comfortable with UIView, UIViewController, Delegates and Sources, like UITableView does for instance. It all makes sense.
Now I have implemented my first real custom view. No XIBs involved. It is an autocomplete address picker very much like in the Mail application. It creates those blue buttons whenever a recipient is added and has all the keyboard support like the original.
It subclasses UIView. There is no controller, no delegate, no source. I wonder if I should have either one of those? Or all, to make it a clean implementation.
I just cannot put my finger on the sense a view controller would make in my case. My custom view acts much like a control and a UIButton doesn't have a controller either.
What would it control in my view's case?
Some of my thoughts:
For the source: currently the view has a property "PossibleAutocompleteRecipients" which contains the addresses it autocompletes. I guess this would be a candidate for a "source" implementation. But is that really worth it? I would rather pass the controller to the view and put the property into the controller.
The selected recipients can be retrieved using a "SelectedRecipients" property. But views should not store values, I learned. Where would that go? Into the controller?
What about all the properties like "AllowSelectionFromAddressBook"? Again, if I compare with UIButton, these properties are similar to the button's "Secure" property. So they are allowed to be in the view.
The delegate could have methods like "WillAddRecipient", "WillRemoveRecipient" and so on and the user could return TRUE/FALSE to prevent the action from happening. Correct?
Should I maybe inherit from UIControl in the first place and not from UIView?
And last but not least: my custom view rotates perfectly if the device is rotated. Why don't all views? Why do some need a controller which implements ShouldAutoRotateToDeviceOrientation()?
Does it make sense what I wrote above? In the end I will provide the source on my website because it took me some time to implement it and I would like to share it as I have not found a similar implementaion of the Mail-App-like autocomplete control in MonoTouch.
I just want to learn and understand as much as possible and include it in the source.
René
I can answer part of your question.
I just cannot put my finger on the
sense a view controller would make in
my case
The ViewController is responsible for handling the View's state transitions (load, appear, rotate, etc) These transitions are used mainly when you use a navigation component (UINavigationViewController, UITabBarController). These components needs to received a ViewController that will handles the view's transitions.
For exemple, when you push a ViewController on a UINavigationViewController, it will cause the ViewDidLoad, ViewWillAppear, ViewDidAppear. It will also cause the ViewWillDisappear, ViewDidDisappear of the current ViewController.
So, if your application has only one portrait view, you don't need a ViewController. You can add your custom view as a subview of the main window.