how to bind fontsize for wpf textbox? - c#

I have a textbox control that works appropriately, without binding, while its font size should be changed dynamically.
I wanted to do it right and work using binding.
I tried to bind the FontSize using (xaml):
<UserControl x:Class="<ClassName>"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Focusable="True"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox x:Name="_textBox" Visibility="Visible" xml:space="preserve"
Background="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=Background}"
Foreground="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=Foreground}"
FontFamily="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=FontFamily}"
BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=BorderBrush}"
Text="{Binding MultilineText}"
FontSize="{Binding Path=MultilineFontSize}"
KeyUp="_textBox_KeyUp"
PreviewTextInput="_textBox_PreviewTextInput"
DataObject.Pasting="_textBox_Pasting"
VerticalContentAlignment="Top"
PreviewKeyDown="TextBox_OnPreviewKeyDown"
TextWrapping="Wrap"
ScrollViewer.VerticalScrollBarVisibility="Visible"
/>
</Grid>
and in the code behind:
private double _multilineFontSize;
public double MultilineFontSize
{
get { return GetBestFittingFontSize(); }
set
{
if (value != _multilineFontSize)
{
_multilineFontSize = value;
OnPropertyChanged("MultilineFontSize");
}
}
}
The only use for _multilineFontSize is to replace _textbox.Text wherever I used it (in events etc).
GetBestFittingFontSize() is a function (that works appropriately) and calculates the font size I need to use. Take it as given. It returns double.
It doesn't work. Does any one have any idea why? (maybe some DataContext issues?)

You can try to use the ViewBox which can be used to scale its content.
<Viewbox StretchDirection="Both" Stretch="Uniform">
<local:UserControl1 Height="100" Width="100"/>
</Viewbox>

Related

How to declare resource before Window in XAML?

My code:
<Window ...
Title="Notification" Height="90" Width="300" ResizeMode="NoResize" WindowStyle="None" DataContext="{Binding Notification, Source={StaticResource Locator}}" Opacity="{Binding TransitionOpacity}" Left="{Binding LeftMargin}" Top="{Binding TopMargin}" Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibility}}">
<Window.Resources>
<local:BoolToVisibleOrHidden x:Key="BoolToVisibility" />
</Window.Resources>
<Grid Background="#FF3C4759">
...
</Window>
While compiling I get exception System.Windows.Markup.XamlParseException and after change code to
<Window ...
Title="Notification" Height="90" Width="300" ResizeMode="NoResize" WindowStyle="None" DataContext="{Binding Notification, Source={StaticResource Locator}}" Opacity="{Binding TransitionOpacity}" Left="{Binding LeftMargin}" Top="{Binding TopMargin}" >
<Window.Resources>
<local:BoolToVisibleOrHidden x:Key="BoolToVisibility" />
</Window.Resources>
<Grid Background="#FF3C4759" Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibility}}">
...
</Window>
it works but I want to set Window visibility instead of Grid.
Binding window visibility might be not a good idea in this case. If you have a notification which you want to hide after some time - just close it (Close()) instead of hiding.
If however you still want to do this - put converter into your application ( App.xaml file). Then you will be able to use it in Window.Visibility binding. As of now - window Visibility property is set before Window.Resources are initialized, so you cannot use converter created inside Window.Resources.
Alternative way is to set Visibility like this:
<Window.Resources>
<local:BoolToVisibleOrHidden x:Key="BoolToVisibility" />
</Window.Resources>
<Window.Visibility>
<Binding Path="IsVisible" Converter="{StaticResource BoolToVisibility}" />
</Window.Visibility>

Why data-binding in Popups don't work, although DataContexts are identical?

As I understand, DataContext is cascaded via the logical tree (or the visual tree, if logical tree is cut off). And if DataContext exists, then data-binding to one of its properties is possible.
And whenever I check it, I see that the Popup's DataContext is the same DataContext object of the root Window object.
Given the above, why data-binding doesn't work with Popups???
Here's the code I used for testing:
<Window x:Class="TestPopup.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:TestPopup"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:ViewModel/>
</Window.DataContext>
<StackPanel>
<Button Margin="10" FontSize="30" Click="Button_OnClick">
<Button.Tag>Positron</Button.Tag>
<TextBlock>
Shoot <Run Text="{Binding Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}}"/>s!
</TextBlock>
</Button>
<Button Margin="10" FontSize="30" Click="Button_OnClick">
<Button.Tag>Tachyon</Button.Tag>
<TextBlock>
Shoot <Run Text="{Binding Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}}"/>s!
</TextBlock>
</Button>
<Popup Name="ThePopup" Placement="Center" StaysOpen="False" AllowsTransparency="True"
PlacementTarget="{Binding RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}}">
<Border Background="White" BorderBrush="Black" BorderThickness="3" CornerRadius="20" Padding="5">
<TextBlock Text="{Binding Charge}" FontSize="30"/>
</Border>
</Popup>
</StackPanel>
</Window>
Code-behind:
namespace TestPopup {
public partial class MainWindow : Window {
ViewModel Vm => (ViewModel) DataContext;
public MainWindow() { InitializeComponent(); }
private void Button_OnClick(object sender, RoutedEventArgs e) {
var munition = ((Button)sender).Tag;
munition = munition == null ? "nothing" : $"{munition}s";
Vm.Charge = $"Emitted {munition}.";
ThePopup.IsOpen = true;
var theTextBox = ThePopup.LogicalChildrenBfs().OfType<TextBlock>().Single();
var theTextBoxDataContext = theTextBox.DataContext;
// they are the same:
var areSame = ReferenceEquals(DataContext, theTextBoxDataContext);
}
}
public class ViewModel : MagicallyHandlesAllINotifyPropertyChanged {
public string Charge { get; set; } = "Initial text";
}
}
DataBinding is cascaded via the visual tree.
Popup is not part of the visual tree.
One way to fix that is adding x:Name to the RootElement (or any other element that has the relevant DataContext) and in the Binding of the popup add ElementName=...
ex:
<Window x:Class="TestPopup.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:TestPopup" **x:Name="MyWindow"**
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:ViewModel/>
</Window.DataContext>
<StackPanel>
<Popup Name="ThePopup" **DataContext="{Binding DataContext, ElementName=MyWindow}"**
Placement="Center" StaysOpen="False" AllowsTransparency="True"
PlacementTarget="{Binding RelativeSource={RelativeSource AncestorType={x:Type Grid}}}">
Popups aren't part of the visual tree, so even if you give them the same DataContext it won't be able to resolve it. The way around this issue is to provide it by way of a proxy binding as explained on this page.

Binding visibility of usercontrol does not collapse control

i do have a problem with binding the visibility of my usercontrol.
The binding to a Dependency Property of type Visibility works fine and the correct value (in this case Collapsed) is held by the DP. The content of my Grid within the UserControl is set to collapsed, but the hole control doesnt collapse. It still keeps the space occupied defined by with and heigth, as referenced in the xaml.
EDIT: i found out, that the problem is that i set width and height in the xaml where i reference my usercontrol. if i don't do this, the control collapses correct (therefore binding works fine). But i need to set width and heigth in case the usercontrol is visible.
Any idea how i can solve this problem?
<my:MenuButtonBase x:Class="bxSuite.Controls.MenuButtonLarge"
xmlns:my="clr-namespace:bxSuite.Controls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Background="Black"
>
<Grid Visibility="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=ButtonVisibility}" >
<StackPanel>
<Image Source="{Binding ButtonImageSource}" Margin="5,10,5,5" Width="48" Height="48" VerticalAlignment="Top" HorizontalAlignment="Center" />
<TextBlock Text="{Binding FunctionHeader}" Foreground="White" TextWrapping="Wrap" TextAlignment="Center" Padding="5,5,5,5" FontSize="12" />
</StackPanel>
</Grid>
</my:MenuButtonBase>
In XAML i reference my usercontrol like this (where the Converter produces the visibility-state correctly):
<my:MenuButtonLarge Name="btnInEuqipment" ButtonVisibility="{Binding Path=User, Converter={StaticResource ConverterUserRightVisibility}, ConverterParameter=5}" VerticalAlignment="Top" FunctionHeader="{lex:Loc Key=MenuButton_InEquipment}" Width="130" ButtonImageSource="/bxSuite.RolloutManager;component/Images/inequipment_48x48.png" BackgroundEnabled="#FF0694FD" BackgroundHover="#FF0072C6" MenuButtonClick="btnInEuqipment_MenuButtonClick" Height="95" Margin="5,10,0,0" />
Try set the visibility of the user control instead of the grid, should work.
Your code should be like this.
<my:MenuButtonBase x:Class="bxSuite.Controls.MenuButtonLarge"
xmlns:my="clr-namespace:bxSuite.Controls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Visibility="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=ButtonVisibility}"
Background="Black">
<Grid>
<StackPanel>
<Image Source="{Binding ButtonImageSource}"
Margin="5,10,5,5"
Width="48"
Height="48"
VerticalAlignment="Top"
HorizontalAlignment="Center" />
<TextBlock Text="{Binding FunctionHeader}"
Foreground="White"
TextWrapping="Wrap"
TextAlignment="Center"
Padding="5,5,5,5"
FontSize="12" />
</StackPanel>
</Grid>
Dont forget to update the RelativeSource of your bind.

How to bind an element to a property which belongs to the root element of a control?

The question may sound a little confusing, but the problem I'm currently facing is this:
<Button x:Class="sandbox.BtnLabel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
x:Name="this">
<Button.ToolTip>
<TextBlock Background="Yellow" Text="{Binding ElementName=this, Path=LabelText}"/>
</Button.ToolTip>
<TextBlock Background="Yellow" Text="{Binding ElementName=this, Path=LabelText}"/>
</Button>
Only the second binding works, which sets the content of the button. The first one, which I would like to use to set the contents of the tooltip of the button (via the LabelText dependency property) does not work.
Is it possible to make the first binding work?
Thanks.
Try this:
<Button x:Class="sandbox.BtnLabel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="this">
<Button.ToolTip>
<ToolTip DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
<TextBlock Background="Yellow"
Text="{Binding LabelText}" />
</ToolTip>
</Button.ToolTip>
<TextBlock Background="Yellow"
Text="{Binding ElementName=this,
Path=LabelText}" />
</Button>
We add a ToolTip element and assign it's DataContext as it's PlacementTarget which should then reach the TextBlock

UserControl inside ContentControl with nested width/height

I'm developing Windows Store App with using Caliburn Micro.
In one of the pages I have ContentControl, which display UserControl. In UserControl I have GridView. My question is: How to set UserControl.Width same as ContentControl.Width? Note: whet set UserControl.Width=Auto - width the same as GridView.Width
in page.xaml
<ContentControl x:Name="ActiveItem" />
in usercontrol.xaml
<UserControl
x:Class="Test.Views.GroupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Width="Auto" Height="Auto">
<Grid Margin="0,20">
<GridView x:Name="Groups" Margin="0" />
</Grid>
</UserControl>
UPDATE
Adding
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
To UserControl doesn't solve the problem.
Figured this out after a lot of trial and error:
<ContentControl Name="MyContent" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
The key is to use the Horizontal/Vertical*Content*Alignment property (not the Horizontal/VerticalAlignment properties).
Here is what you should do when problem like your's appears.
Try to set ContentControl's Background property to some disturbing color. For example Purple or Pink. And also set Background property on your UserControl for example Green. It will allow you to see where exactly is your ContentControl and where is UserControl. If you can't see any Green you can tell that content of UserControl is stretched to fill whole UserControl.
Try to set UserControl's VerticalAlignment and HorizontalAlignment properties to Stretch. FrameworkElement.HorizontalAlignment, VerticalAlignment
Note: In order to let these work. You can't explicitly set Width and Height on your UserControl.
Try to set ContentControl's VerticalContentAlignment and HorizontalContentAlignment to Stretch. Control.HorizontalContentAlignment, VerticalContentAlignment . These stretches the child element to fill the allocated layout space of the parent element.
If you still see some Purple or Pink then something's wrong again :) you can check Margin/Padding MSDN
If it's still messed up. Then I don't know how else can I help you. Last possible solution would be binding. And I am not sure if it works.
<UserControl
Width="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ContentControl}},
Path=ActualWidth}"
Height="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ContentControl}},
Path=ActualHeight}">
...
</UserControl>
I hope something helps. I believe you that it could be really annoying problem.
Especially for #AlexeiMalashkevich
I solve it with using binding like this:
In root Page you have:
<ContentControl x:Name="ActiveItem"/>
Then add the child page:
<Page
Height="{Binding ActualHeight, ElementName=ActiveItem}"
Width="{Binding ActualWidth, ElementName=ActiveItem}"
......
/>
And that's all.
You should be able to bind UserControl's width to the ContentControl's ActualWidth.
<local:MyUserControl1 Height="50" Width="{Binding ElementName=contentControl, Path=ActualWidth}"/>
Here is some sample code:
<Page
x:Class="stofUserControlWidth.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:stofUserControlWidth"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="Cyan"/>
<ContentControl Grid.Column="1" x:Name="contentControl">
<local:MyUserControl1 Height="50" Width="{Binding ElementName=contentControl, Path=ActualWidth}"/>
</ContentControl>
</Grid>
</Page>
Here is MyUserControl1.xaml code:
<UserControl
x:Class="stofUserControlWidth.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:stofUserControlWidth"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid Background="Magenta">
</Grid>
</UserControl>
Hope this helps!
For me this is working:
<UserControl
...
Height="{Binding ActualHeight,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentControl}}}">
...
</UserControl>
You have to make sure that your ContentControl has the desired size.
For example my ContentControl look like this: It is always fill the whole size of the window. And the size of the UserControl in the ContentControl dinamically changes as well.
<Grid>
<ContentControl HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" DataContext="{Binding StartViewModel}" Name="ContentArea" />
</Grid>

Categories