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:
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?
Thank you sir for your reply. I suggest you to see my full question because I clearly tell there what I want to do. OK again I tell you. I want to bind the Text block Font Size with the button Font Size and with application.current state. I clearly written in my question that as First binding and second binding.
 
But there is only one font size to be set. You have to choose what value you will set it to.
 
I know that, That's why I use Multibinding. I want to bind the Font Size with two properties. These two binding work perfectly when I use them separately. But I want to combine them using a Multibinding.
 
Let me put it this morning way: there is only one keyhole, but you have two keys. You are asking that both keys be put into the keyhole. That won't work. You can use the multi binding to either pick one of the keys to use, or to create a brand new key that is a combination of the two keys.

Your averaging code above tries to create that combination, but obviously that doesn't work. What value are you computing as a combination?
 
Let me put it this morning way: there is only one keyhole, but you have two keys. You are asking that both keys be put into the keyhole. That won't work. You can use the multi binding to either pick one of the keys to use, or to create a brand new key that is a combination of the two keys.

Your averaging code above tries to create that combination, but obviously that doesn't work. What value are you computing as a combination?
Thank you sir for your enormous effort to answer my question. This is my fault that I misunderstood the concept of Multi binding in WPF. Now you can just suggest me that how I can achieve that, I just want to get the Font Size =10 in the Text block and at that same time I want to bind with application.current state. Is there any other way? to get this in my application. Please tell me.
 
Back
Top Bottom