I have a grid with 2 rows and 4 columns with width and height as specified below. Second row has only one control in col=1 and that control may or may not present(due to some logic).
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions></Grid>
When control is not present:
Since second row is height is "Auto" and when I have no control, I'll have only single row. In that case, I need to have specific margin with respect to grid bottom.
Hence, Margin of row 0 control = "0,0,0,14"
When control is present:
When control is present, I have two rows and I need to have margin between two row elements as 6px and second row margin should be 14 w.r.t bottom of grid.
Hence, Margin of row 0 control = "0,0,0,6" and Margin of row 1 control = "0,0,0,14"
How could I achieve these different margin values based on second row presence. Please help. Thanks in advance.
Refer img:
For your requirement, you could use MarginConverter to set row 0 control margin base on the row 1 control's present or not.
For example
public class MarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
Thickness newMargin;
var visibility = (Visibility)value;
switch (visibility)
{
case Visibility.Visible:
newMargin = new Thickness(0, 0, 0, 6);
break;
case Visibility.Collapsed:
newMargin = new Thickness(0, 0, 0, 14);
break;
default:
break;
}
return newMargin;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Usage
<Page.Resources>
<local:MarginConverter x:Key="Conveter" />
</Page.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle
Grid.Row="0"
Grid.Column="1"
Margin="{Binding ElementName=Row1Control, Path=Visibility, Converter={StaticResource Conveter}}"
Fill="Red" />
<Rectangle
x:Name="Row1Control"
Grid.Row="1"
Grid.Column="1"
Height="80"
Margin="0,0,0,14"
Fill="Black"
Visibility="Visible" />
</Grid>
Update
But in my case, Row1Control is dynamically set in the backend.
you could detect RootGrid LayoutUpdated event, if you add the control it will be invoked, then re-set MarginProperty in the following method.
private int oldCount;
private void RootGrid_LayoutUpdated(object sender, object e)
{
if(RootGrid.Children.Count > oldCount)
{
if (RootGrid.Children.Any(p => p.GetValue(NameProperty).ToString() == "Row1Control"))
{
Row0Control.SetValue(MarginProperty, new Thickness(0, 0, 0, 6));
}
else
{
Row0Control.SetValue(MarginProperty, new Thickness(0, 0, 0, 14));
}
oldCount = RootGrid.Children.Count;
}
}
Add element in the code behind.
private void Button_Click(object sender, RoutedEventArgs e)
{
var Row1Control = new Rectangle() { Height = 80, Margin = new Thickness(0, 0, 0, 14), Fill = new SolidColorBrush(Colors.Black), Name = "Row1Control" };
Row1Control.SetValue(Grid.ColumnProperty, 1);
Row1Control.SetValue(Grid.RowProperty, 1);
RootGrid.Children.Add(Row1Control);
}
Related
Please help with CarouselView.
Xaml:
<carousel:CarouselViewControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Source="{Binding ImSource}" Aspect="AspectFill" Grid.Row="0" Grid.RowSpan="3" HeightRequest="220"/>
<Button
Grid.Row="0"
Text="1/1"
CornerRadius ="40"
FontSize="10"
HorizontalOptions="End"
BackgroundColor="Black"
TextColor="White"
WidthRequest="40"
HeightRequest="20"
Margin="0, 10, 10, 0"
Opacity="0.7"
Padding="0"/>
<controls:CircleImage
Grid.Row="2"
Source="users.png"
HorizontalOptions="Start"
WidthRequest="22"
Opacity="0.7"
Margin="10, 0, 0, 10"/>
</Grid>
</DataTemplate>
</carousel:CarouselViewControl.ItemTemplate>
</carousel:CarouselViewControl>
On my Button I need to display current position in Carousel.
But if in list one image - need to hide this button.
Button text must be like - 2(position)/3(list.Count)
I used: https://github.com/alexrainman/CarouselView
Please tell me - how I can do this.
Try to bind carousel position property to your ViewModel and then bind text from ViewModel to your button. So, something like this for CarouselViewControl:
<carousel:CarouselViewControl x:Name="CarouselView"
Position="{Binding CarouselPosition}"
ItemsSource="{Binding CarouselViewItems}">
...
</carousel:CarouselViewControl>
Your Button:
<Button
Grid.Row="0"
Text="{Binding CarouselPositionDisplayCounter}" .../>
In your ViewModel, add properties like it follows.
Carousel's current position:
private int _carouselPosition;
public int CarouselPosition
{
get { return _carouselPosition; }
set
{
_carouselPosition = value;
OnPropertyChanged();
}
}
Text binded to button:
public string CarouselPositionDisplayCounter =>
$"{(CarouselPosition + 1).ToString()}/{CarouselViewItems.Count.ToString()}";
And command when swiped:
public ICommand CarouselSwipedCommand => new Command(() =>
{
OnPropertyChanged(nameof(CarouselPositionDisplayCounter));
});
The carouselView already comes with it's own implementation of what you want:
You just need to add the ShowIndicators property to your xaml declaration:
<controls:CarouselViewControl ShowIndicators="True" ... />
Also there are properties for specifying shape and color of the indicators:
IndicatorsTintColor: page dot indicators fill color (default #C0C0C0).
CurrentPageIndicatorTintColor: selected page dot indicator fill color (default #808080).
IndicatorsShape: Indicators shape (default Circle).
I have a listview in which i have data, in listview i have
1 - taskname
2- date
3 - completed percentage
4 - Assigned task by
I want to put condition in list and based on condition want to change color of list row, for example if completed percentage =0, color of that row should be white if percentage is greater then 0 color should be red etc etc.
check image down below:
in listview i have 0%, 7% and 100 %, so i want if its 0 row color should be white, if its more then 0 row color should b red and if its = 100 row color should be green here is my xaml code
<ListView HeightRequest="20" HasUnevenRows="True" SeparatorColor="Red" ItemsSource="{Binding GetAssignedTask}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Grid.Column="0" Source="rsz_pnglogocom.png" />
<Label Grid.Row="0" Grid.Column="1" Text="{Binding strTaskName}" TextColor="Black" FontSize="Medium" />
<Label Grid.Row="1" Grid.Column="1" Text="{Binding intCurrCompletePercentage , StringFormat='{0}% Completed '}" Margin="0,0,10,0" TextColor="Black" />
<Label Grid.Row="1" Grid.Column="2" Margin="0,0,20,0" Text="{Binding dtStart,StringFormat='{0:MMMM dd, yyyy}'}" TextColor="Red" HorizontalOptions="Center"/>
<Label Grid.Row="1" Grid.Column="3" Text="{Binding strAssignedByEmpName}" TextColor="Black" HorizontalOptions="End"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Two ways to do this.
1. Using Converters:
Create a Value converter:
public class BackgroundColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
if(value!=null)
{
if((int)value ==0)
return Color.White;
else if((int)value > 0)
return Color.Red;
else
return Color.Green;
}
}
catch (Exception ex)
{
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
xaml part:
xmlns:converter="RefrenceToConverterNameSpace"
<ContentPage.Resources>
<ResourceDictionary>
<converter:BackgroundColorConverter x:Key="BackgroundColorConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<Grid BackgroundColor="{Binding intCurrCompletePercentage,Converter={StaticResource BackgroundColorConverter}}" />
Method 2:
In your object which containts intCurrCompletePercentage
You can also have another property Color property PercentColor
public Color PercentColor
{
get
{
if(intCurrCompletePercentage ==0)
return Color.White;
else if(intCurrCompletePercentage > 0)
return Color.Green;
else
return Color.Red;
}
}
<Grid BackgroundColor="{Binding PercentColor}" />
Whenever your intCurrCompletePercentage changes dont forget to call the propertychanged event for PercentColor.
You could also have a look at DataTemplateSelector for this case.
A look in the documentation https://learn.microsoft.com/de-de/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/selector
Code from documentation
public class PersonDataTemplateSelector : DataTemplateSelector
{
public DataTemplate ValidTemplate { get; set; }
public DataTemplate InvalidTemplate { get; set; }
protected override DataTemplate OnSelectTemplate (object item, BindableObject container)
{
return ((Person)item).DateOfBirth.Year >= 1980 ? ValidTemplate : InvalidTemplate;
}
}
XAML
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="validPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="invalidPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<local:PersonDataTemplateSelector x:Key="personDataTemplateSelector"
ValidTemplate="{StaticResource validPersonTemplate}"
InvalidTemplate="{StaticResource invalidPersonTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
<ListView x:Name="listView" ItemTemplate="{StaticResource personDataTemplateSelector}" />
You would have to make 3 templates (ZeroTemplate, AboveZeroTemplate, HundredTemplate) and let your DataTemplateSelector decide which template it should take.
I posted just the documentation code, because I think you always should do something on yourself to also learn something, and not just copy paste.. :)
First of all YES I've read all the suggested "Questions that may already have your answer", so I belive this is not a dublicate.
I have this grid on a Page:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="Please sign below." Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Image x:Name="SignImage" />
</Grid>
<Grid Background="Transparent" Grid.Row="2" Margin="12,0,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="10"/>
</Grid.ColumnDefinitions>
<Button x:Name="ClearButton" Content="Clear" Grid.Column="1"/>
<Button x:Name="OkButton" Content="Ok" Grid.Column="2"/>
</Grid>
</Grid>
Then this CodeBehind:
public MainPage()
{
InitializeComponent();
this.Loaded += MainPage_Loaded;
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
}
....
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
MessageBox.Show($"SignImage.ActualWidth: {SignImage.ActualWidth}, SignImage.ActualWidth: {SignImage.ActualWidth} ");
}
The problem is that the size of my Image is 0 (zero).
How do I make my Image fill out the cell I've placed it in?
First there is difference between * and Auto. Please do check the size of the main grid. "*" means stretch to fill the available space, and is a fraction, so if one row is * and the other row is 2* then the second row will be twice the size of the first row.
Auto means it takes whatever/or only space it needs.
If you have set the size of whole Grid to a small height then there will be a problem. Set the MinHeight for the Main Grid component.
Second you have not set the image for SignImage with a size which mean you will obviously get ActualWidth and ActualHeight as Zero. The image tag is empty in which no Source is set.
<Image x:Name="SignImage" Source="C:\Users\Administrator\Pictures\user-thumbnail.png"/>
Check after setting the image source if you are getting the ActualWidth and ActualHeight
Have a look at this image I have written your code. You can see that for Grid 0 and 2 there is Height set for Grid 1 there is no Height set as you have written * for it so it is necessary to set the height to parent.
Now look at this image I have set the height for the parent element as 200 and hence you can see the Gird 1 is visible and the height is not 0.
So it is necessary to set the height or set the image source for the height not to be zero.
I know that this question has been posted about a thousand times, but I did not find a solution that solved my problem.
I've got a LongListSelector with this ItemTemplate:
<DataTemplate x:Key="AddrBookItemTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock FontWeight="Bold" Text="{Binding Name}" HorizontalAlignment="Stretch" VerticalAlignment="Center" Grid.Column="0" Grid.Row="0" />
<Button x:Name="itembutton" CommandParameter="{Binding ItemID}" Content="{Binding ButtonCaption}" Width="150" HorizontalAlignment="Right" Grid.Column="1" Grid.Row="0" Click="ItemButtonClick"/>
</Grid>
</DataTemplate>
So what happens is simply that I get this beautiful error message that I posted in the title. And I do not have a clue, why?!
private void ItemButtonClick(object sender, RoutedEventArgs e)
{
if (sender == this.itemButton) {
....
From the DataTemplate it looks like you're showing this button in a container like a ListBox or LongListSelector.
That means that there isn't an itembutton in this scope (presumably this is either UserControl or PhoneApplicationPage): there is in fact one for each of your ListBoxItems!
You'll have to find another way of finding your button.
Update:
You should find that the DataContext of your button matches the item of the list it is contained in. That's probably the easiest way of proceeding: however if all else fails you can use the Tag property as you suggest.
Like:
private void ItemButtonClick(object sender, RoutedEventArgs e)
{
var theButton = (Button) sender;
var myItem = (TypeOfAnObjectInMyList) theButton.DataContext;
doSomethingWithMyItem(myItem);
I've been using grids to hold my controls for a new app. Such as;
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Label1:" />
<ListBox Grid.Row="0" Grid.Column="1" />
<Label Grid.Row="1" Grid.Column="0" Content="Label2:" />
<ComboBox Grid.Row="1" Grid.Column="1" />
<Label Grid.Row="2" Grid.Column="0" Content="Label3:" />
<TextBox Grid.Row="2" Grid.Column="1" />
</Grid>
This works fine however I've now got a situation where I only want to show my third row based upon the selectedvalue from the combobox in the second row.
With a grid this seems a bit messy too set the visibilty of the entire row to be collapsed. I think I'd have to do it by setting the hight of the contents of the row to zero.
Is there a more flexible layout that the grid. I thought about the stackpannel but wasn't sure about having multiple columns and keeping the rows in synch.
This is probably a really simple question but I'm interested to get input from other people before I do anything.
I wouldn't recommend setting the height of controls to zero - for one thing, it would still be possible to tab to a 0-height control which would be confusing for users to say the least :)
As an alternative, try binding the visibility of any affected controls to the combobox selection, e.g:
<UserControl xmlns:cnv="clr-namespace:your_namespace_here">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Label1:" />
<ListBox Grid.Row="0" Grid.Column="1" />
<Label Grid.Row="1" Grid.Column="0" Content="Label2:" />
<ComboBox Name="cbo" Grid.Row="1" Grid.Column="1" />
<Label Grid.Row="2" Grid.Column="0" Content="Label3:"
Visibility="{Binding ElementName=cbo, Path=SelectedIndex,
Converter={cnv:IntToVisibilityConverter}}" />
<TextBox Grid.Row="2" Grid.Column="1" />
</Grid>
In code, put together a converter which returns the relevant Visibility type:
namespace your_namespace_here
{
public class IntToVisibilityConverter : MarkupExtension, IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int _value = (int)value;
return (_value > 0) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
}
Note that in this example, the converter will return Visiblity.Collapsed if the first item in the combo is selected, otherwise Visiblity.Visible.
Untested code, but the method is sound. Hope this is of some use!