Within a Xamarin.Form page, I am trying to bind the FontSize of a label to the height of that same label.
I seen examples in WPF that do this:
FontSize="{Binding ElementName=CurrentPresenter, Path=Height}"
But I can not seem to get anything to work like that in Forms, i.e.:
<Label
Text="X"
FontSize="{Binding ElementName=CurrentPresenter, Path=RequestedHeight}"
HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutBounds="0.1, 0.5, 0.33, 0.66"
AbsoluteLayout.LayoutFlags="All" />
(I will use a data converter to adjust the font size so based upon screen DPI, I can auto-adjust, but for now, I'm just trying to bind it to a control's height to get something other than default system font size)
This way appears to work fine, not sure about the runtime layout performance though...
FYI: This does not work within the XAML Designer, only runtime
<Label
Text="X"
x:Name="foo"
BindingContext="{x:Reference Name=foo}"
FontSize="{Binding Path=Height}"
HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutBounds="0.1, 0.5, 0.33, 0.66"
AbsoluteLayout.LayoutFlags="All" />
Not exactly related to OP question but searching "Xaml height based on another control" has hardly any results in Google so posting this in case it helps someone else.
To change the size of smaller buttons to match the size of a larger button like in the following picture
There are several ways to do this without using code behind but if the layout you are trying to use is being difficult here following is another option. To change the size of the smaller buttons without changing the binding of those controls you can give the buttons names in XAML and then do something like this in the code behind:
public HomeOpenPage ()
{
InitializeComponent ();
RefreshButton.PropertyChanging += RefreshButton_PropertyChanging;
}
private void RefreshButton_PropertyChanging(object sender, PropertyChangingEventArgs e)
{
if (RefreshButton.Width != -1)
{
var width = RefreshButton.Width;
CSVButton.WidthRequest = width;
EndButton.WidthRequest = width;
}
}
protected override void OnDisappearing()
{
RefreshButton.PropertyChanging -= RefreshButton_PropertyChanging;
base.OnDisappearing();
}
Related
I have a button with MinWidth set as MinWidth="118" and that works fine. But when I change the Text size in windows using Settings -> Accessibility -> Text Size -> change it to 200%, then text takes more space and that hard coded width is not sufficient so text gets cut off. So how can I set the width so that text never cuts off? Also, I do not want to calculate the new width for 200% text size because, the text of the button can change without making any code changes since that text is service delivered. So is there any way to set the width so that text on the button never cuts off?
<Button
MinWidth="118"
MinHeight="30"
HorizontalAlignment="Left"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
AutomationProperties.Name="{x:Bind ViewModel.PrimaryActionAutomationName, Mode=OneWay}"
BorderThickness="1"
Click="{x:Bind ViewModel.InvokePrimaryAction}"
Content="{x:Bind ViewModel.PrimaryAction, Mode=OneWay}"
CornerRadius="3"
Style="{StaticResource AccentButtonStyle}" />
Thanks
So is there any way to set the width so that text on the button never cuts off?
No, there is no such built-in feature for the Button control. You still need to manage the Button width on your own. Handle the DisplayInformation.DpiChanged Event and get the current ResolutionScale value. Then you could change the width based on the value.
MainPage.h
struct MainPage : MainPageT<MainPage>
{
MainPage();
private:
Windows::Graphics::Display::DisplayInformation displayInfo{ nullptr };
event_token DpiChangedToken{};
void OnDpiChanged(Windows::Graphics::Display::DisplayInformation const&, Windows::Foundation::IInspectable const&);
};
MainPage.cpp
MainPage::MainPage()
{
InitializeComponent();
displayInfo = DisplayInformation::GetForCurrentView();
DpiChangedToken = displayInfo.DpiChanged({ get_weak(), &MainPage::OnDpiChanged});
}
void MainPage::OnDpiChanged(DisplayInformation const&, IInspectable const&)
{
DisplayInformation displayInformation = DisplayInformation::GetForCurrentView();
ResolutionScale scale = displayInformation.ResolutionScale();
// switch logic here
}
My code will draw a graphic and, before the paint event, I need to set the size of element containing the graphic. In part, this comes from a value in an XAML file:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="35" />
</Grid.RowDefinitions>
...
</Grid>
During the view initialization, I'm hoping to be able to modify the graphic width based on some other factors, but I need the height value, from XAML.
At a breakpoint, I can view the various View values, and at this point ActualHeight and ActualWidth are still 0. I don't see anything else I could use.
Is there another event, coming before paint, that I could use ?
The answer is to use SizeChanged event.
In XAML, for example:
<skia:SKXamlCanvas
x:Name="EICanvas"
SizeChanged="OnSizeChanged" />
And in code-behind:
private void OnSizeChanged (Object sender, SizeChangedEventArgs e)
{
var newH = e.NewSize.Height;
var oldH = this.ActualHeight; // in pixels
...
}
Is it possible to have an Image take 100% width of its parent container while actually fitting the whole image within this container without clipping, and while having height automatically adjusted to preserve aspect ratio?
I have read similar questions both on SO and Xamarin Forums but apparently this cannot be done without implementing custom renderers or manually calculating correct sizes in code. But to calculate this in code you would need either image dimensions or aspect ratio. For applications where neither of these are known before head, this is a problem.
In terms of CSS, the solution I am looking for is similar to having
width:100%; height:auto;
Implementing a custom renderer for such a trivial task is an overkill and a huge embarrassment for Xamarin in my opinion; unless I am understanding something wrong.
I have searched for an answer to this problem for a long time. As others have noted, I did not find a Xaml-only solution. I choose a different route and present my solution for those who might find it instructive and as the seed for changes to FFImageLoading to solve this correctly.
I created a subclass of CachedImage and overrided OnMeasure. In order for CachedImage.OnMeasure to work in the aspect modes (not fill mode), it has to return a SizeRequest which matches the ratio of the underlying image. So the solution I chose was simply to use the provided widthConstraint and calculate the height as widthConstraint / ratio. This description only addresses one of the many cases: where the widthConstraint is not infinity and the desire is to answer the specific question posed here (width of 100% and auto height).
A subclass which implements this case:
public class CachedImage2 : CachedImage
{
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
var sr = base.OnMeasure(widthConstraint, heightConstraint);
if (sr.Request.IsZero)
return sr;
var ratioWH = sr.Request.Width / sr.Request.Height;
var sr2 = new SizeRequest(new Size(widthConstraint, widthConstraint / ratioWH));
return sr2;
}
}
I was unable to find a pure XAML solution to this problem and therefore decided to use ffimageloading's Success event to find out the original width and height of loaded image and get aspect ratio from these values, store it, and use it in SizeAllocated event to maintain aspect ratio of the image while making sure its width is 100% of the parent container.
Sample code:
private void testImage_OnSuccess(object sender, CachedImageEvents.SuccessEventArgs e)
{
var image = sender as CachedImage;
double width = e.ImageInformation.OriginalWidth;
double height = e.ImageInformation.OriginalHeight;
ratio = width / height; // store it in a variable
}
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
if (this.Width > 0 && ratio != 0) // width of the parent container
testImage.HeightRequest = this.Width / ratio;
}
Presuming when you say:
and while having height automatically adjusted..
You mean the height of the container.
Yes this is completely possible in Xamarin.Forms.
Let's imagine I have a Grid as my parent container. Here is how I would do it.
<!-- remove all the padding & margin & spacing on Grid -->
<Grid RowSpacing="0"
ColumnSpacing="0"
Margin="0"
Padding="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <!-- the containers height will now adjust -->
<RowDefinition Height="56"/> <!-- This one is for the other content in your view etc -->
</Grid.RowDefinitions>
<!-- Put your image inside your parent container and apply properties -->
<Image Source="some_source.png"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"/>
</Grid>
The Horizontal and vertical options are as if you are setting width:100% and height: 100% in CSS.
Put you Image in a frame. And then set the height and width of image accprding to the frame.
<Frame>
<Image></Image>
</Frame>
You could change the width and height according to your frame via binding Value Converters.
Binding Value Converters: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/converters
Set the name to your Frame first.
<Frame
…………
x:Name="frame"/>
Create the MyConverter. You could change the percentage of value in Convert method.
MyConverter.cs
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Set the StaticResource.
<ContentPage.Resources>
<ResourceDictionary>
<local:MyConverter x:Key="MyConverter" />
</ResourceDictionary>
Binding to your image.
<Image WidthRequest="{Binding Source={x:Reference frame},Path=Width,Converter={StaticResource MyConverter}}"
HeightRequest="{Binding Source={x:Reference frame},Path=Height,Converter={StaticResource MyConverter}}"></Image>
I'm struggling with new UWP InkCanvas for my apps.If you are familiar with the new InkCanvas in UWP, I would truly appreciate your help.
I have a UWP apps need to switching between InkCanvas and Canvas, which I wish to use InkCanvas for Drawing, Canvas for creating Contents such as RichEditbox, Image, etc...
My XAML is below
<Grid Margin="100,0,100,0" Background="White" x:Name="MainGrid" PointerMoved="MyCanvas_PointerMoved" PointerReleased="MyCanvas_PointerReleased" PointerPressed="MyCanvas_PointerPressed">
<Canvas x:Name="MyCanvas" />
<InkCanvas x:Name="inkCanvas" Canvas.ZIndex="0" />
<!-- End "Step 2: Use InkCanvas to support basic inking" -->
</Grid>
I tried to make my Canvas ZIndex greater than InkCanvas by using
private void AppBarButton_Click(object sender, RoutedEventArgs e)
{
if(Canvas.GetZIndex(MyCanvas) > 1)
{
Canvas.SetZIndex(MyCanvas, 0);
}
else
{
Canvas.SetZIndex(MyCanvas, 5);
}
}
However I can't make my Canvas come to the front, the InkCanvas keep Capturing my stroke if I Draw on it instead.
Does anyone know how to switch the Canvas and InkCanvas in my Grid without changing the Visibility of my InkCanvas to Collapsed?
By default the Canvas background is empty (null), so it will not capture pointer input and will pass it through to the InkCanvas.
If you want to prevent this, you could set its Background to Transparent.
However, when you start putting some controls on the Canvas itself, they should capture the pen input and not let it through to the InkCanvas.
I am trying to put floating popup windows on screen. I want user to be able to move that popup window anywhere on the screen.
And so I am using:
<Popup x:Name="myPopup" Grid.Row="0" Grid.RowSpan="2" Margin="0, 0, 0, 0" ManipulationMode="All" ManipulationDelta="PopupManipulationDelta" IsLightDismissEnabled="False" Visibility="Collapsed" IsOpen="false">
code behind:
private void PopupManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
var ct = (CompositeTransform)addShapesPopup.RenderTransform;
ct.TranslateX += e.Delta.Translation.X;
ct.TranslateY += e.Delta.Translation.Y;
UpdateLayout();
}
But this is not working. The function PopupManipulationDelta is not even getting called.
I tried using same logic on shapes like rectangle, ellipse and it works fine there.
Can you please help me understand why it's not working with popup?
Thank you.
I believe a Popup does not have any visual representation, so it can't respond to hit testing and thus to manipulation events. Simply put some control inside of it and have that respond to the input events. It can be a Grid with Background="Transparent" if you don't want it to be visible.