Can't find variable for button inside if/else - c#

I want to have a different margin for iOS and Android so I tried to make if/else but the MyButton cannot be found when then button is inside the if/else like this:
if (Device.RuntimePlatform == Device.iOS)
{
var MyButton = new Button
{
Margin = new Thickness(0, -15, 0, 0)
};
}
else
{
var MyButton = new Button
{
Margin = new Thickness(-10, -15, 0, 0)
};
}
var MyStackLayout = new StackLayout
{
Children = { MyButton }
};
The name MyButton does not exist in the current context.
Is there a work around or a different method for this?

change your code as below:
Button MyNewButton;
if (Device.RuntimePlatform == Device.iOS)
{
MyNewButton= new Button
{
Margin = new Thickness(0, -15, 0, 0)
};
}
else
{
MyNewButton= new Button
{
Margin = new Thickness(-10, -15, 0, 0)
};
}
var MyStackLayout = new StackLayout
{
Children = { MyNewButton}
};
When you define a variable in if body, it cannot be access in out of if body.
And if you declare variable with the same name (Mybutton), change this button name.

As it was mentioned multiple times, the problem is that MyButton is living in a wrong scope. What is a scope?
The scope of a variable determines its visibility to the rest of a
program. In the examples throughout the C# Fundamentals tutorial,
variables have been defined within methods. When created in this way,
the scope of the variable is the entire method after the declaration.
This means that the variable is available to use within the method but
when control passes to another method the variable is unavailable.
You can read more about it here.

Related

Add click gesture recognizer on stack child (item in scroll)

I've got a stack layout inside a gridview, that I use as a sort of list.
The "items" in the list have to be click/tap -able, but I can't find a way to make the child area clickable while also giving a value to the event to know what item the user clicked.
Right now I create 20 items in a for loop. The "i" is an integer used for counting.
I put an BoxView over the original boxview and label of the item, which is transparent and gets the gesturerecognizer.
var clickableBoxv = new BoxView
{
BackgroundColor = Color.Transparent,
Margin = new Thickness(0, 5, 0, 5)
};
clickableBoxv.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() => Item_Clicked(i)),
});
private void Item_Clicked(int num)
{
DisplayAlert("Alert", num.ToString(), "OK");
}
But when I click the item, it shows an alert with only the last added number. (which didn't surprise me). But how can I get the alert to show me the specific item number?
While I haven't tested your exact code I have reproduced the same behaviour with some Actions inside a for loop.
Option 1 - Track the boxes.
It might not be the most ideal of solutions but one option would be to keep track of your boxes and use their index in the collection to represent the number.
// 1. A place to store the boxes.
IList<BoxView> boxes = new List<BoxView>();
var clickableBoxv = new BoxView
{
BackgroundColor = Color.Transparent,
Margin = new Thickness(0, 5, 0, 5)
};
// 2. Keep track of your clickable boxes.
boxes.Add(clickableBoxv);
clickableBoxv.GestureRecognizers.Add(new TapGestureRecognizer
{
// 3. Pass in the box rather than the int.
Command = new Command(() => Item_Clicked(clickableBoxv)),
});
private void Item_Clicked(BoxView box)
{
// 4. Use the index as the number.
DisplayAlert("Alert", boxes.IndexOf(box).ToString(), "OK");
}
Option 2 - sub class BoxView
// 1. Sub class
public class MyBoxView : BoxView
{
public int Index { get; set; }
}
// 2. Use new sub class
var clickableBoxv = new MyBoxView
{
BackgroundColor = Color.Transparent,
Margin = new Thickness(0, 5, 0, 5),
Index = i,
};
clickableBoxv.GestureRecognizers.Add(new TapGestureRecognizer
{
// 3. Pass in the box rather than the int.
Command = new Command(() => Item_Clicked(clickableBoxv)),
});
private void Item_Clicked(MyBoxView box)
{
// 4. Use the index as the number.
DisplayAlert("Alert", box.Index.ToString(), "OK");
}

Create line use BoxView in Xamarin Forms

I need to create a line which is a made up of multiple BoxViews (WidthRequest=0.20830 and HeightRequest=5 for every BoxView). There will be 1440 BoxViews in a sequence arranged in way that it will create a line(approximately WidthRequest=300).
My Code -
public partial class timeManagement : ContentPage
{
double oneMinute=0.20833333;
public timeManagement ()
{
InitializeComponent ();
StackLayout stack = new StackLayout{Orientation=StackOrientation.Horizontal,
};
for(int i=1;i<=14;i++)
{
BoxView piece_ofLine = new BoxView
{
HeightRequest=5,
WidthRequest=5,
Color=Color.Red
};
if (i >= 5 && i <= 9) {
stack.Children.Add (piece_ofLine);
piece_ofLine.Color = Color.Green;
} else {
stack.Children.Add (piece_ofLine);
piece_ofLine.Color = Color.Red;
}
}
Content = new StackLayout {
Padding =50,
Spacing=0,
Children = {
stack
}
};
}
}
And output is-
But I want all boxes side by side so it will appear like a single line.
There are a few issues here
The default orientation for a StackLayout is Vertical so you would need to set that on the stack variable
You would need to create a new instance for each BoxView that you add to the stack. Otherwise it will just keep adding the same one over and over. And in the end you would just have one.
I assume that you would want them directly to the side of each other. If this is the case, I think that it would be safest to explicitly set the Spacing of your StackLayout to 0

C# XNA if-else and defaulting to first value

So I am developing a custom ButtonGUI class for my game. Here's the initialization of the button object:
// Button code:
ButtonGUI btn1 = new ButtonGUI("Button 1", new Rectangle(150, 300, (int)myFont.MeasureString(menuButtons[0]).X, (int)myFont.MeasureString(menuButtons[0]).Y), myFont, Color.CornflowerBlue);
Now consider this code:
// Draw() method:
btn1.Draw(spriteBatch);
if (btnHover)
{
btn1.btnRect = new Rectangle(140, 300, (int)hoverFont.MeasureString(menuButtons[0]).X, (int)hoverFont.MeasureString(menuButtons[0]).Y);
btn1.btnFont = hoverFont;
btn1.btnColour = Color.Red;
}
else
{
btn1.btnRect = new Rectangle(150, 300, (int)myFont.MeasureString(menuButtons[0]).X, (int)myFont.MeasureString(menuButtons[0]).Y);
btn1.btnFont = myFont;
btn1.btnColour = Color.CornflowerBlue;
}
This would be OK if I had only 1 button... But if I have like 10 buttons or more? This really isn't what DRY suggests. I feel like I'm missing something, there must be a way to return button properties to their default values once the condition is no longer met without doing the whole thing manually, or is there? Thanks in advance!
It may make sense to create a structure to hold all of the values that may change.
class ButtonData
{
// put members corresponding to each member of ButtonGUI you wish
// to change
}
class ButtonSwapper
{
ButtonGUI myButton;
ButtonData hoverData;
ButtonData notHoverData;
void change(bool hover)
{
ButtonData dataToUse = hover ? hoverData : notHoverData;
// set each relevant member of myButton to its pair in
// dataToUse
}
}
then call change as necessary.

Use variable value as x:Name

I have a button called myBtn. in XAML: ( <Button x:Name="myBtn" ... )
I have also a variable, which value is myBtn
Now, I need change this button's color:
public string buttonName = "myBtn";
private void method ()
{
this.buttonName.Background = new SolidColorBrush(Color.FromRgb(255, 0, 255));
}
This gives error:
string does not contain definition for Background
What is right syntax to do this?
Try this:
public Button buttonName;
private void method ()
{
buttonName = this.FindName("myBtn") as Button;
buttonName.Background = new SolidColorBrush(Color.FromRgb(255, 0, 255));
}
myBtn.Background = new SolidColorBrush(Color.FromRgb(255, 0, 255));
Once you give the control the x:Name attribute, you can refer to it directly from code behind without doing anything else.
You can access the background color of a named XAML button by using
myBtn.Background = new SolidColorBrush(Color.FromRgb(255, 0, 255));
The name you specify becomes a Button object for the code-behind in the application you are building.

Common class for WPF Containers (Canvas, Grid, etc)

I am creating a method that is invoked by a button. The method then adds a canvas to the button's parent container control. So, e.g., the button is on a grid. Then the method creates a canvas that is shown just below the button. But I have 2 issues:
How can I get a reference to the button's parent container?
Is there a class for container controls? I don't care if the button is in a grid, a canvas, a Stackpanel, etc. So I am looking for an interface that all types of contianers implement or a class that they inherit.
The second aspect is more important as I could pass a reference to the container manually.
EDIT:
It should look like this (minus the colors, those are only to show the different elements.
The red canvas is supposed to pop up to handle a confirmation. Maybe even with a nice animation. My idea was to create a class that can be invoked similar to this:
MyPopup popup = new MyPopup("Are you sure?", "Yes", "No", delegateFirstButton, delegateSecondButton);
popup.Show();
My code so far is not yet a class but only a method. The text parts are hard coded for the moment. The marked line needs to be more flexible and is the reason for my question.
public void ShowPopup(Control senderControl)
{
//I need to have a parameter that accepts all containers instead of this line:
this.myGrid.Children.Add(popup);
Border border = new Border();
popup.Children.Add(border);
border.Margin = new Thickness() { Top = 10 };
border.Child= text;
text.Text = "Are you sure?";
text.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
popup.SizeChanged += delegate { border.Width = popup.ActualWidth; };
popup.Children.Add(btn1);
btn1.Content = "Yes";
btn1.Height = 22;
btn1.Padding = new Thickness(10, 0, 10, 0);
btn1.Margin = new Thickness() { Left = 15, Top = 35 };
popup.Children.Add(btn2);
btn2.Content = "No";
btn2.Height = 22;
btn2.Padding = new Thickness(10, 0, 10, 0);
btn1.SizeChanged += delegate { btn2.Margin = new Thickness() { Left = 30 + btn1.ActualWidth, Top = 35 }; };
popup.Height = 70;
btn2.SizeChanged += delegate
{
popup.Width = 45 + btn1.ActualWidth + btn2.ActualWidth;
updatePositions(senderControl);
};
popup.Background = Brushes.Red;
popup.VerticalAlignment = System.Windows.VerticalAlignment.Top;
popup.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
}
public void updatePositions(Control senderControl)
{
Point location = senderControl.TranslatePoint(new Point(0, 0), this.myGrid);
popup.Margin = new Thickness()
{
Left = location.X + (senderControl.ActualWidth / 2) - (popup.Width / 2),
Top = location.Y + senderControl.ActualHeight + 15
};
}
Sounds like you're choosing the hard way to do that.
If you need a popup, then use a Popup.
Otherwise, if for whatever reasons you don't want to use that, You'd better place a grid somewhere near the root of your XAML, and ALWAYS use that as a container:
<Window>
<Grid x:Name="MainUI"/>
<Grid x:Name="PopupContainer"/>
</Window>
Otherwise, you'll almost invariably encounter Z-Index problems (if you follow your current approach).
Also, it's a really bad idea to create all that UI stuff in code. Either encapsulate your Yes/No dialog in a UserControl or create a proper Template for that.
As I said before, avoid at all costs creating/manipulating UI elements in code, as it creates a lot of maintainability issues.

Categories