How to Bind FontSize of a TextBlock from two different sources in WPF?

merun372

Member
Joined
Jan 31, 2021
Messages
11
Programming Experience
Beginner
Due to design purpose I use the fluid Layout which is mainly made by Grid.Row definition. I want to adjust my WPF application to run smoothly on every monitor that's why I use the DPI Decorator class. And this DPI Decorator is perfectly working that means the screen UI components are perfectly resizing according to the screen DPI but the main problem is related to the text rendering. The text are became blurry when I run my WPF application in lower screen resolution.

Though I successfully solve this problem by the data binding of the Font Size of the Text Block to the x:Static Application.Current. And now If I run my application in lower screen resolution my text perfectly scaled and no blurry and rendering issue is present.

But I want to scale the Text at a specific Font Size because in Segoe UI, different Font Size have different letter looks and spacing. And in my case I use the Font Size 10 and then scale it using View Box.

And my main problem is, I have to bind the Font Size from two different sources. In the First binding I have to bind the button Font Size with Text Block Font Size because in my case the Text Block is inside it's parent container button. So, that if I declare Font Size 10 in the button then by using the data binding the Text Block automatically inheritate the property from it's parent container Button.

And the second binding is with the application state UI, as I say previously. So, that it's perfectly scale into any screen DPI and screen resolution.


The only solution is I have to do a Multi data Binding with a specific converter to satisfy those data binding condition. I also tried that but that not working properly.


Here is the code of First data binding where I bind the Text Block Font Size with x:Static Application.Current. to overcome the blurry issue of the text in different DPI -

All of my Button are made by my own control template. First I bind the source with x:Static Application.Current in my control template.

Here is the part of the code of my button control template -

Button Control Template:
<Style
                 x:Key="RoundCorner"
                 x:Name="RoundCornerButton"
                 TargetType="{x:Type Button}">
             <Setter Property="HorizontalContentAlignment" Value="Center" />
             <Setter Property="VerticalContentAlignment" Value="Center" />
             <Setter Property="Padding" Value="1" />
             <Setter Property="Foreground" Value="#bababa" />
             <Setter Property="ToolTipService.InitialShowDelay" Value="500" />
             <Setter Property="ToolTipService.ShowDuration" Value="4000" />
              
             <Setter Property="FontFamily" Value="Segoe UI"/>
             <Setter Property="FontSize">
                 <Setter.Value>
                     <Binding Source="{x:Static Application.Current}" Path="fontSize"/>
                 </Setter.Value>
             </Setter>


As you clearly see that I use the Path fontSize to bind with Application.current state.

And later I use in the Text Block. Here is the code -

Use in Button:
<Button
      
         x:Name="BtnSettings" Width="90" HorizontalAlignment="Left" Margin="200,14,0,0" Height="30" DockPanel.Dock="Left" FontSize="10"
      VerticalAlignment="Top"  UseLayoutRounding="True"  RenderOptions.ClearTypeHint="Enabled"  RenderOptions.BitmapScalingMode="NearestNeighbor"   SnapsToDevicePixels="True"     
                                   >
                     <Button.Content >
                         <Viewbox Height="15" SnapsToDevicePixels="True" StretchDirection="Both"   x:Name="myViewbox"  Stretch="Uniform"  HorizontalAlignment="Stretch"  >
  
                             <TextBlock x:Name="myTextbox"                                     
                                 FontSize="{Binding Source={x:Static Application.Current}, Path=fontSize, Mode=TwoWay}"                                   
                                        SizeChanged="myTextbox_SizeChanged"
                                        FontFamily="Segoe UI" UseLayoutRounding="True" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="NearestNeighbor"  TextOptions.TextFormattingMode="Display"       Margin="0,-2,0,0" TextOptions.TextRenderingMode="ClearType"  RenderOptions.ClearTypeHint="Enabled"                                >                 
                                          
                     Settings
                         </TextBlock>
  
                         </Viewbox>
                     </Button.Content>
                 </Button>



And the second binding is with the Text Block Font Size with Button Font Size because I have to maintain the Font Size 10 scale -
Binding with the TextBlock in that button:
<Button
        
             x:Name="BtnSettings" Width="90" HorizontalAlignment="Left" Margin="200,14,0,0" Height="30" DockPanel.Dock="Left" FontSize="10"
          VerticalAlignment="Top"  UseLayoutRounding="True"  RenderOptions.ClearTypeHint="Enabled"  RenderOptions.BitmapScalingMode="NearestNeighbor"   SnapsToDevicePixels="True"     
                                       >
                         <Button.Content >
                             <Viewbox Height="15" SnapsToDevicePixels="True" StretchDirection="Both"   x:Name="myViewbox"  Stretch="Uniform"  HorizontalAlignment="Stretch"  >
                                 <TextBlock x:Name="myTextbox"                                     
                                     FontSize="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}, Path=FontSize}"                                   
                                            SizeChanged="myTextbox_SizeChanged"
                                            FontFamily="Segoe UI" UseLayoutRounding="True" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="NearestNeighbor"  TextOptions.TextFormattingMode="Display"       Margin="0,-2,0,0" TextOptions.TextRenderingMode="ClearType"  RenderOptions.ClearTypeHint="Enabled"                                >                 
                                              
                         Settings
                             </TextBlock>
                             </Viewbox>
                         </Button.Content>
                     </Button>



Now the goal is to use a Multi data binding to satisfy those both data binding condition -

As much as I tried this is the code -

MultiBinding For button:
<Button
      
         x:Name="BtnSettings" Width="90" HorizontalAlignment="Left" Margin="200,14,0,0" Height="30" DockPanel.Dock="Left" FontSize="10"
      VerticalAlignment="Top"  UseLayoutRounding="True"  RenderOptions.ClearTypeHint="Enabled"  RenderOptions.BitmapScalingMode="NearestNeighbor"   SnapsToDevicePixels="True"     
                                   >
                     <Button.Content >
                         <Viewbox Height="15" SnapsToDevicePixels="True" StretchDirection="Both"   x:Name="myViewbox"  Stretch="Uniform"  HorizontalAlignment="Stretch"  >
                             <TextBlock x:Name="myTextbox"                                     
                                                                      
                                        SizeChanged="myTextbox_SizeChanged"
                                        FontFamily="Segoe UI" UseLayoutRounding="True" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="NearestNeighbor"  TextOptions.TextFormattingMode="Display"  Margin="0,-2,0,0" TextOptions.TextRenderingMode="ClearType"  RenderOptions.ClearTypeHint="Enabled" >
                                        
                                         <TextBlock.FontSize>
  
                                     <MultiBinding Converter="{StaticResource AverageConverter}">
                                         <Binding Source="{x:Static Application.Current}" Path="fontSize" Mode="TwoWay" />
                                         <Binding Path="FontSize"  RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}" />
                                     </MultiBinding>
  
                                 </TextBlock.FontSize>
                                          
                     Settings
                         </TextBlock>
                         </Viewbox>
                     </Button.Content>
                 </Button>

Here is the code of that AverageConverter -

Multivalue Converter:
namespace WpfApp1
 {
     class AverageConverter : IMultiValueConverter
     {
  
         #region IMultiValueConverter Members
         public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
         {
             int total = 0;
             int number = 0;
             foreach (object o in values)
             {
                 int i;
                 bool parsed = int.TryParse(o.ToString(), out i);
                 if (parsed)
                 {
                     total += i;
                     number++;
                 }
             }
             if (number == 0) return 0;
             return (total / number).ToString();
         }
  
         public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
         {
             throw new NotImplementedException();
         }
  
         #endregion
  
     }
 }

My question is how to use Multi Data Binding to satisfy those both data binding condition ? Because my Multi Data binding is not working.
 
Last edited by a moderator:
Is your AverageConverter even being called?
 
Is your AverageConverter even being called?
Right sir, I know that there some error in my converter that's why it's not called properly. Can you please modify the code of my Average Converter because I have to code it properly so that it helps in multi binding and interact with my data.
 
If there's an error in the converter, your code would either not compile, or it would compile be throw an error. This is why I was asking if your converter is even being called. You just ignored the question.
 
If there's an error in the converter, your code would either not compile, or it would compile be throw an error. This is why I was asking if your converter is even being called. You just ignored the question.
Please give me a proper way to implement this data binding.
 
You have the correct approach. Is your converter being called?
 
You have the correct approach. Is your converter being called?
Thank you sir. Yes, my converter is called perfectly. As I say previously my converter code is not perfect that means there no error in the code but the code is not applicable in this scenario. Please do some code modification for me.
 
Please do some code modification for me.
We are not a code writing service. We help you figure out what maybe going wrong, but we won't do your work for you.

So if your converter is being called, what value are you returning as the size? Is that the value you were expecting? Is WPF using that size that you returned?
 
As an aside, I have some doubts about you forcing font sizes for different DPI's. WPF is supposed to be high DPI aware and you shouldn't have to bend over backwards to make things work like you have to in WinForms. Perhaps it's your choice of fixed font sizes instead of just telling WPF what you control sizes, padding, and margins are and let it figure out the appropriately scaled font should be.
 
As an aside, I have some doubts about you forcing font sizes for different DPI's. WPF is supposed to be high DPI aware and you shouldn't have to bend over backwards to make things work like you have to in WinForms. Perhaps it's your choice of fixed font sizes instead of just telling WPF what you control sizes, padding, and margins are and let it figure out the appropriately scaled font should be.
I already tested WPF high dpi default properties and it does not working for me. If you kindly know how to code for the converter then that will be a great help for me.
 
You have to help us help you. What is your converter returning? What value were you expecting?
 
You have to help us help you. What is your converter returning? What value were you expecting?
I just want the Text block get the Font size of it's parent button container and also it can bind with application.current state. I just want this two binding run successfully, I have nothing to do with the converter.
 
Then write your converter to follow that logic. Currently, it looks like you are trying to compute the average of the bound values.

As I was asking earlier, what value is your converter returning? Why is this a hard question? Do you not know how to set a breakpoint and debug to inspect values?
 
Then write your converter to follow that logic. Currently, it looks like you are trying to compute the average of the bound values.

As I was asking earlier, what value is your converter returning? Why is this a hard question? Do you not know how to set a breakpoint and debug to inspect values?
Thank your sir, for your reply. After applying the converter only one data binding is working. And that is the binding the application.current state. But the second binding where I bind with the Relative source to the button the get the Font size of the button, that is not working. Kindly please tell me that how both binding can work at a same time?
 
First you say that you want it to bind to only one value. Now you want to bind to both. Perhaps what you meant to say is that you want it to bind to one value in one situation, and a different value in another situation? If not, then what are you seeking?
 
Back
Top Bottom