How to trigger converter programatically

BitSmithy 1,751 Reputation points
2020-05-05T18:51:02.987+00:00

Hello,

I have TextBox binded to other UIElement property. The TextBox shows value of this property.

        Windows.UI.Xaml.Data.Binding bc1 = new Windows.UI.Xaml.Data.Binding() { Path = new PropertyPath("Width") };
        bc1.Mode = BindingMode.TwoWay;
        bc1.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
        tbx.SetBinding(TextBox.TextProperty, bc1);

        bc1.Converter = new MeasureUnitsConverter();

I want to trigger MeasureUnitsConverter() converter in ComboBox event SelectionChanged

        <ComboBox x:Name="cmb"                           
                  ItemsSource="{x:Bind MeasureUnitsList}"
                  SelectedIndex="0"
                  SelectionChanged="cmb_SelectionChanged"
                  ></ComboBox>

How to do such task?

Universal Windows Platform (UWP)
{count} votes

Accepted answer
  1. Daniele 1,996 Reputation points
    2020-05-07T18:14:58.513+00:00

    Lookin at your code, in my opinion, using the Converter is not the right approach when the ComboBox selection changes. It is ok when the Width changes, but for the unit of measure I would do this:

    Change the converter in this way, this is to have a common code usable by the converter and by code behind:

    public class MeasureUnitsConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return Convert(value);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            //From TextBox to UIElement (From string to double)
    
            /* Under construction
                if (value == null)
                    return 0;
                else if (mu == "epx")
                    return value;
                else if (mu == "inch")
                    return (double)value * 96;
                else if (mu == "mm")
                    return (double)value * 96 * 24.5;
            else
            */
            return value;
        }
    
        public static string Convert(object value)
        {
            //From UIElement to TextBox (from double to string)
            if (value == null)
                return "0.00";
            else if (mu == "epx")
                return value.ToString(); //epx
            else if (mu == "inch")
                return ((double)value / 96).ToString(); //epx
            else if (mu == "mm")
                return ((double)value / 96 * 25.4).ToString(); //epx
            else
                return value.ToString();
        }
    }
    

    then change cmb_SelectionChanged in this way

    private void cmb_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (sender is ComboBox cmb)
        {
            if (rect == null) return;
            mu = cmb.SelectedValue.ToString();
            tbx.Text = MeasureUnitsConverter.Convert(rect.Width);
        }
    }
    
    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2020-05-05T20:44:44.227+00:00

    Hi, raise PropertyChanged:

    : INotifyPropertyChanged
      {
    ...
        private void cmb_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
          OnPropChanged(nameof(Width));
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropChanged([CallerMemberName] string propertyName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    

  2. Peter Fleischer (former MVP) 19,231 Reputation points
    2020-05-07T19:35:08.617+00:00

    Hi, your problem is DataContext of tbx. In following demo I change DataContext and binding to other property.

    <Page
        x:Class="Change_MeasureUnit_Test.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Change_MeasureUnit_Test"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
      <StackPanel>
        <TextBox x:Name="tbx"/>
        <ComboBox x:Name="cmb" ItemsSource="{Binding MeasurmentUnitsList}"/>
      </StackPanel>
    </Page>
    
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Data;
    
    namespace Change_MeasureUnit_Test
    {
      public sealed partial class MainPage : Page, INotifyPropertyChanged
      {
        public static string[] MeasurmentUnits = { "epx", "mm", "inch" };
        public List<string> MeasurmentUnitsList
        { get { return MeasurmentUnits.ToList(); } }
    
        public static string mu = "epx";
    
        public MainPage()
        {
          this.InitializeComponent();
    
          this.DataContext = this;  <------------------------
    
          //tbx.DataContext = rect; //rect is Shapes.Rectangle defined in MainPage.xaml  <-----------------
    
          Binding bc1 = new Binding() { Path = new PropertyPath("WidthValue") };  <---------------------
    
          bc1.Converter = new MeasureUnitsConverter();
    
          bc1.Mode = BindingMode.TwoWay;
          bc1.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
          tbx.SetBinding(TextBox.TextProperty, bc1);
    
          cmb.SelectionChanged += cmb_SelectionChanged;
    
          tbx.LostFocus += tbx_LostFocus;
        }
    
        public double WidthValue { get; set; } = 100;  <-------------------------------------
    
        private void cmb_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
          if (sender is ComboBox cmb)
          {
            mu = cmb.SelectedValue.ToString();
            OnPropChanged(nameof(WidthValue));  <---------------------------
          }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropChanged([CallerMemberName] string propertyName = "") =>
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    
        private void tbx_LostFocus(object sender, RoutedEventArgs e)
        {
          BindingExpression cbe = tbx.GetBindingExpression(TextBox.TextProperty);
          cbe.UpdateSource();
        }
    
    
        public class MeasureUnitsConverter : IValueConverter
        {
          public object Convert(object value, Type targetType, object parameter, string language)
          {
            //From UIElement to TextBox (from double to string)
            if (value == null)
              return 0.00;
            else if (mu == "epx")
              return value; //epx
            else if (mu == "inch")
              return (double)value / 96; //epx
            else if (mu == "mm")
              return (double)value / 96 * 25.4;//epx
            else
              return value;
          }
    
          public object ConvertBack(object value, Type targetType, object parameter, string language)
          {
            //From TextBox to UIElement (From string to double)
    
            /* Under construction
                if (value == null)
                    return 0;
                else if (mu == "epx")
                    return value;
                else if (mu == "inch")
                    return (double)value * 96;
                else if (mu == "mm")
                    return (double)value * 96 * 24.5;
            else
            */
            return value;
          }
        }
      }
    } 
    
    0 comments No comments