locked
TextBlock dynamic binding RRS feed

  • Question

  • I have a WPF TextBlock bound to a string using Dynamic resourse. If that string is null, I want the TextBlock to display binding value.

    <TextBlock  Text="{DynamicResource keyState}" >

    if keyState=null, i want to display "keyState" as text.

    Is there anyway to implement this in XAML?

    Thanks in advance.

    Tuesday, July 30, 2013 4:30 AM

Answers

  • Instead of adding a bunch of resources to the window, you could expose the dictionary through a property a bind to this use using a converter:

      public partial class MainWindow : Window
      {
        public MainWindow() {
          InitializeComponent();
        }
        public Dictionary<string, string> ResourcesList {
          get;
          set;
        }
      }
      public static void loadResource(MainWindow window)
      {
       ....//load from db as before..
     window.ResourcesList = resourceList;
      }
      public class DictConverter : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
          Dictionary<string, string> resources = value as Dictionary<string, string>;
          string key = parameter as string;
          if (resources != null && !string.IsNullOrEmpty(key) && resources.ContainsKey(key))
            return resources[key];
          return key;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
          throw new NotImplementedException();
        }
      }

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
      <local:DictConverter x:Key="dictConverter"/>
    </Window.Resources>
    <Grid>
     <TextBlock Text="{Binding Path=ResourcesList, Converter={StaticResource dictConverter}, ConverterParameter=keyState54543, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
    </Grid>
    </Window>

    • Marked as answer by Kelums Wednesday, August 7, 2013 12:37 PM
    Wednesday, August 7, 2013 12:16 PM
  • Hello, Here Convert method only fire when page load. I want to fire it for combo box selection change event occurs. I try but not works. How can I do that?

    Thanks in advance!


    By implementing the INotifyPropertyChanged interface and raise the PropertyChanged event when the CombBox selection changes:

    public partial class MainWindow : Window, INotifyPropertyChanged
      {
        public MainWindow() {
          InitializeComponent();
        }
        
        public Dictionary<string, string> ResourcesList {
          get;
          set;
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs args)
        {
            ....
     NotifyPropertyChanged("ResourcesList"); //tells the view to query the get accessor again
        }
      }

    • Marked as answer by Kelums Friday, August 9, 2013 3:27 PM
    Friday, August 9, 2013 12:35 PM

All replies

  • if possible share what is there in Keystate resource and where did you declare.

    as i see you are using dynamic resource, then you can check whether keystate exists or not, if not do something else.


    Thanks & Regards
    Syed Amjad Sr. Silverlight/WPF Developer,
    yahoo : syedamjad6736@yahoo.com, skype : syedamjad.0786.
    Please use Marked as Answer if my post solved your problem and use Vote As Helpful if a post was useful.

    Tuesday, July 30, 2013 9:23 AM
  • As there is no TargetNullValue to be set for a DynamicResource the easiest way is probably to avoid setting the value of the resource to NULL:

    string keyState = this.Resources["keyState"] as string;
    if(some condition)
     keyState = "keyState";
    

    Tuesday, July 30, 2013 9:44 AM
  • This is a case for a ValueConverter. Below is a complete but ugly example you can copy into a new project and try:

    <Window x:Class="WpfApplication112.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525"
            xmlns:local="clr-namespace:WpfApplication112">
        <Window.Resources>
            <local:NullConverter x:Key="NullConverter"/>
        </Window.Resources>
        <StackPanel>
            <TextBlock Text="{Binding Text1, Converter={StaticResource NullConverter}, ConverterParameter=keyState}"/>
            <TextBlock Text="{Binding Text2, Converter={StaticResource NullConverter}, ConverterParameter=keyState}"/>
            <TextBlock Text="{Binding Text3, FallbackValue=No binding}"/>
        </StackPanel>
    </Window>
    


    using System;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfApplication112
    {
        public partial class MainWindow : Window
        {
            public string Text1 { get; set; }
            public string Text2 { get; set; }
    
            public MainWindow()
            {
                InitializeComponent();
                Text1 = "Hello cruel world";
    
                DataContext = this;
            }
        }
    
        public class NullConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return value == null ? parameter : value;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    
    }
    

     

    The first TextBlock has some text in the bound property

    The second has a bound property but is null

    The third is an example of if the bound property is missing (FalbackValue)

     

    Regards,
    Pete


    #PEJL Got a good solution? If you invest your time in coding an elegant/novel or large answer on these MSDN forums, why not copy it over to our beloved TechNet Wiki, for future generations to benefit from!

    Tuesday, July 30, 2013 3:32 PM
  • This is a case for a ValueConverter.


    Converters can be used to change data from one type to another and provide a way to apply custom logic to a data binding but you cannot use bindings on a DynamicResource as it does not derive from the DependencyObject class.
    • Marked as answer by Kelums Tuesday, August 6, 2013 1:55 PM
    • Unmarked as answer by Kelums Tuesday, August 6, 2013 1:55 PM
    Tuesday, July 30, 2013 3:40 PM
  • Doh, silly me, rush read fail. Thanks for pointing out my mistake Magnus.

    In that case, this could be a case for an Attached Property...

    <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication112" 
            xmlns:System="clr-namespace:System;assembly=mscorlib" 
            x:Class="WpfApplication112.MainWindow"
            Title="MainWindow" Height="350" Width="525"
            >
        <Window.Resources>
            <System:String x:Key="String1">hi</System:String>
            <x:Static x:Key="String2" Member="System:String.Empty" />
        </Window.Resources>
    
        <StackPanel>
    
            <TextBlock Text="{DynamicResource String1}" local:Attached.AltNullValue="keyState" />
            <TextBlock Text="{DynamicResource String2}" local:Attached.AltNullValue="keyState" />
    
        </StackPanel>
    </Window>


    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfApplication112
    {
        class Attached
        {
            public static string GetAltNullValue(DependencyObject obj)
            {
                return (string)obj.GetValue(AltNullValueProperty);
            }
    
            public static void SetAltNullValue(DependencyObject obj, string value)
            {
                obj.SetValue(AltNullValueProperty, value);
            }
    
            public static readonly DependencyProperty AltNullValueProperty =
                DependencyProperty.RegisterAttached("AltNullValue", typeof(string), typeof(Attached), new UIPropertyMetadata(null, AltNullValueChanged));
    
            static void AltNullValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                var tb = sender as TextBlock;
                tb.Loaded += new RoutedEventHandler(tb_Loaded);
            }
    
            static void tb_Loaded(object sender, RoutedEventArgs e)
            {
                var tb = sender as TextBlock;
                if (string.IsNullOrWhiteSpace(tb.Text))
                    tb.Text = tb.GetValue(Attached.AltNullValueProperty).ToString();
            }
    
        }
    }

    Of course this will only work on first load. If your DynamicResource truly is dynamic (meaning it changes at run time) then you could restyle a TextBox to look like a TextBlock and also hook into the TextChanged event as shown below:

     

    <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication112" 
            xmlns:System="clr-namespace:System;assembly=mscorlib" 
            xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" 
            x:Class="WpfApplication112.MainWindow"
            Title="MainWindow" Height="350" Width="525"
            >
        <Window.Resources>
            <System:String x:Key="String1">hi</System:String>
            <x:Static x:Key="String2" Member="System:String.Empty" />
    
            <Style x:Key="TextBoxStyle1" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
            	<Setter Property="Template">
            		<Setter.Value>
            			<ControlTemplate TargetType="{x:Type TextBox}">
            				<TextBlock Text="{TemplateBinding Text}" />
            			</ControlTemplate>
            		</Setter.Value>
            	</Setter>
            </Style>
        </Window.Resources>
    
        <StackPanel>
            <TextBox Text="{DynamicResource String1}" Style="{DynamicResource TextBoxStyle1}" local:Attached.AltNullValue="keyState"/>
            <TextBox Text="{DynamicResource String2}" Style="{DynamicResource TextBoxStyle1}" local:Attached.AltNullValue="keyState"/>
        </StackPanel>
    </Window>


    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfApplication112
    {
        class Attached
        {
            public static string GetAltNullValue(DependencyObject obj)
            {
                return (string)obj.GetValue(AltNullValueProperty);
            }
    
            public static void SetAltNullValue(DependencyObject obj, string value)
            {
                obj.SetValue(AltNullValueProperty, value);
            }
    
            public static readonly DependencyProperty AltNullValueProperty =
                DependencyProperty.RegisterAttached("AltNullValue", typeof(string), typeof(Attached), new UIPropertyMetadata(null, AltNullValueChanged));
    
            static void AltNullValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                var tb = sender as TextBox;
                tb.Loaded += new RoutedEventHandler(tb_Loaded);
                tb.TextChanged += new TextChangedEventHandler(tb_TextChanged);
            }
    
            static void tb_Loaded(object sender, RoutedEventArgs e)
            {
                CheckText(sender);
            }
    
            static void tb_TextChanged(object sender, TextChangedEventArgs e)
            {
                CheckText(sender);
            }
    
            static void CheckText(object sender)
            {
                var tb = sender as TextBox;
                if (string.IsNullOrWhiteSpace(tb.Text))
                    tb.Text = tb.GetValue(Attached.AltNullValueProperty).ToString();
            }
        }
    }

     

    My reason for this approach is to make something that is generic, reusable and doesn't clutter the code.

     

    Regards,
    Pete

    PS, I know I use a Static in this example, but that is just as I found issues trying to add a null string as a resource and haven't the time to fix that, but that's obviously not your actual issue.

     


    #PEJL Got a good solution? If you invest your time in coding an elegant/novel or large answer on these MSDN forums, why not copy it over to our beloved TechNet Wiki, for future generations to benefit from!


    • Edited by Pete LakerMVP Tuesday, July 30, 2013 4:51 PM added ps
    • Proposed as answer by Leo (Apple) Yang Tuesday, August 6, 2013 11:33 AM
    • Unproposed as answer by Kelums Wednesday, August 7, 2013 6:47 AM
    Tuesday, July 30, 2013 4:35 PM
  • Hello, 

    I stored textblock's text in  a table  and it has two columns called "_key","_value". keyState is a value inside a _key column and there is a value inside the _value column against keyState. When I binding textblock text property as keyState , run time it loading _value column data . I used this technic to implement Localization. I want show binding value(keyState) as Textblock text when database not having a value against keyState.

    Thanks in advance.

    Monday, August 5, 2013 9:54 AM
  • Table? Do you mean a DataTable?

    Then I think your original method using DynamicResource is wrong, and we are back to my original ValueConverter example:

        public class TableConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                //return value matching the key from table, else return key
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }


    <TextBlock  Text="{Binding MyTable, Converter={StaticResource TableConverter}, ConverterParameter=KeyName1}" >

     

    If this doesn't answer your question, you will have to paste some code to illustrate your problem so we can reproduce your problem

     

    Regards,
    Pete


    #PEJL Got a good solution? If you invest your time in coding an elegant/novel or large answer on these MSDN forums, why not copy it over to our beloved TechNet Wiki, for future generations to benefit from!


    • Edited by Pete LakerMVP Monday, August 5, 2013 6:01 PM typo
    • Proposed as answer by Leo (Apple) Yang Tuesday, August 6, 2013 11:33 AM
    • Unproposed as answer by Kelums Wednesday, August 7, 2013 6:47 AM
    Monday, August 5, 2013 6:00 PM
  • Hello,

    Thanks for all of your's answer's. But still not solved my question. 

    I stored labels data in a table of the database.

    I binding those data into dictionary list against a window.

            public static void loadResource(System.Windows.Window window)
            {

                    string query = @"SELECT * FROM Common_Resource_Detail
                                    WHERE Common_Resource_Detail.PAGE_NAME = '" + window.Title)+ "'";

                    using (SqlConnection sqlConnection = new SqlConnection(connectionString))
                    {
                        sqlConnection.Open();
                        SqlCommand sqlCommand = new SqlCommand(query, sqlConnection);
                        SqlDataReader dataReader;
                        dataReader = sqlCommand.ExecuteReader();

                        while (dataReader.Read())
                        {
                          Dictionary<string, string> = resourceList.Add(dataReader.GetString(dataReader.GetOrdinal("LABEL_KEY")), dataReader.GetString(dataReader.GetOrdinal("LABEL_VALUE")));
                        }
                        dataReader.Close();
                        dataReader.Dispose();
                    }

    //I binding resourceList to resource of the page

                foreach (var item in resourceList)
                {
                   window.Resources.Add(item.Key, item.Value);
                }

    In the XAML,

            <TextBlock    Text="{DynamicResource keyState}"  >

    hele keyState is in the LABEL_KEY column of the database.

    when page loading above TextBox text is a LABEL_VALUE column data which is against LABEL_KEY 

    this working when keyState in the LABEL_KEY  column and it has a value in LABEL_VALUE column.

    I want to show keyState as text of the TextBlock when keyState is not exist in the LABEL_KEY  colomn of the database table.

    Thanks in advance.

    Tuesday, August 6, 2013 4:21 AM
  • Instead of adding a bunch of resources to the window, you could expose the dictionary through a property a bind to this use using a converter:

      public partial class MainWindow : Window
      {
        public MainWindow() {
          InitializeComponent();
        }
        public Dictionary<string, string> ResourcesList {
          get;
          set;
        }
      }
      public static void loadResource(MainWindow window)
      {
       ....//load from db as before..
     window.ResourcesList = resourceList;
      }
      public class DictConverter : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
          Dictionary<string, string> resources = value as Dictionary<string, string>;
          string key = parameter as string;
          if (resources != null && !string.IsNullOrEmpty(key) && resources.ContainsKey(key))
            return resources[key];
          return key;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
          throw new NotImplementedException();
        }
      }

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
      <local:DictConverter x:Key="dictConverter"/>
    </Window.Resources>
    <Grid>
     <TextBlock Text="{Binding Path=ResourcesList, Converter={StaticResource dictConverter}, ConverterParameter=keyState54543, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
    </Grid>
    </Window>

    • Marked as answer by Kelums Wednesday, August 7, 2013 12:37 PM
    Wednesday, August 7, 2013 12:16 PM
  • Thanks Magnus. Its work fine now. :)
    Wednesday, August 7, 2013 12:39 PM
  • Hello, Here Convert method only fire when page load. I want to fire it for combo box selection change event occurs. I try but not works. How can I do that?

    Thanks in advance!

    Friday, August 9, 2013 12:05 PM
  • Hello, Here Convert method only fire when page load. I want to fire it for combo box selection change event occurs. I try but not works. How can I do that?

    Thanks in advance!


    By implementing the INotifyPropertyChanged interface and raise the PropertyChanged event when the CombBox selection changes:

    public partial class MainWindow : Window, INotifyPropertyChanged
      {
        public MainWindow() {
          InitializeComponent();
        }
        
        public Dictionary<string, string> ResourcesList {
          get;
          set;
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs args)
        {
            ....
     NotifyPropertyChanged("ResourcesList"); //tells the view to query the get accessor again
        }
      }

    • Marked as answer by Kelums Friday, August 9, 2013 3:27 PM
    Friday, August 9, 2013 12:35 PM