views:

1872

answers:

2

Hi!

I'm doing a list of contacts for a person.

I have an ItemsControl which uses DataTemplates for different types of contact information. E.g. Phone number, Email... etc

In case of phone number, I want user to have 4 TextBoxes where he can edit the number. 4 because of the format (he can edit numbers only, the format is generated automatically):

+43 (2) 112233 - 2

each part as a TextBox. AND I want to have a main TextBox with the whole number written in that format. That means when a user edits one of those 4 Textboxes, the main TextBox is in real time filled with a formatted number.

I got it working in code behind, but as I'm using DataTemplates now, I want to reach this functionality in XAML. Any Idea how to add triggers to all those 4 TextBoxes in way the main TextBox is regenerated with a correct format?

+1  A: 

You should be able to bind each TextBox to the same underlying property, and use a converter with the intelligence to extract out the part of the phone number relevant to that TextBox. Pseudo-code:

<TextBox Text="{Binding PhoneNumber, Converter={StaticResource PhoneNumberConverter, ConverterParameter=CountryCode}}"/>
<TextBox Text="{Binding PhoneNumber, Converter={StaticResource PhoneNumberConverter, ConverterParameter=AreaCode}}"/>
...

If you're doing MVVM, use separate properties in a PhoneNumberViewModel rather than using a converter.

HTH, Kent

Kent Boogaart
OK but what if I edit one of those Textboxes? The underlying value change, but UI of the main TextBox will not update. Or? I think it's not going to be notified.
PaN1C_Showt1Me
To handle the notification, look into the INotifyPropertyChanged interface: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
Richard C. McGuire
OK thank you.. I decided to use MVVM for this purpose.. as it is much easier to do changes :)
PaN1C_Showt1Me
+1  A: 

If I got this correctly and you don't necessarily need to edit the phone number in the main TextBox, you can use multibinding to accomplish this. Here is an example:

<DataTemplate x:Key="PhoneNumberTemplate">
  <StackPanel Orientation="Horizontal">
    <TextBox Name="tbPN1" />
    <TextBox Name="tbPN2" />
    <TextBox Name="tbPN3" />
    <TextBox Name="tbPN4" />
    <TextBox IsReadOnly="True">
      <TextBox.Text>
        <MultiBinding StringFormat="{}+{0} ({1}) {2} - {3}">
          <Binding Path="Text" ElementName="tbPN1" UpdateSourceTrigger="PropertyChanged" />
          <Binding Path="Text" ElementName="tbPN2" UpdateSourceTrigger="PropertyChanged" />
          <Binding Path="Text" ElementName="tbPN3" UpdateSourceTrigger="PropertyChanged" />
          <Binding Path="Text" ElementName="tbPN4" UpdateSourceTrigger="PropertyChanged" />
        </MultiBinding>
      </TextBox.Text>
    </TextBox>
  </StackPanel>
</DataTemplate>

This will update the main TextBox every time a key is pressed inside one of the other 4 TextBoxes

Update:
In order to 'update' the data source, I would do the following:

Have the PhoneNumber class implement INotifyPropertyChanged like this:

public class PhoneNumber : INotifyPropertyChanged {

  public event PropertyChangedEventHandler PropertyChanged;

  private void OnPropertyChanged(string propertyName) {
    var handler = PropertyChanged;
    if (handler != null) {
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
  }

  private string m_CountryCode;
  public string CountryCode {
    get { return m_CountryCode; }
    set {
      m_CountryCode = value;
      ComputeFullNumber();
      OnPropertyChanged("CountryCode");
    }
  }

  private string m_AreaCode;
  public string AreaCode {
    get { return m_AreaCode; }
    set {
      m_AreaCode = value;
      ComputeFullNumber();
      OnPropertyChanged("AreaCode");
    }
  }

  private string m_Number;
  public string Number {
    get { return m_Number; }
    set {
      m_Number = value;
      ComputeFullNumber();
      OnPropertyChanged("Number");
    }
  }

  private string m_Suffix;
  public string Suffix {
    get { return m_Suffix; }
    set {
      m_Suffix = value;
      ComputeFullNumber();
      OnPropertyChanged("Suffix");
    }
  }

  public string FullNumber { get; private set; }

  private void ComputeFullNumber() {
    FullNumber = string.Format("+{0} ({1}) {2} - {3}", m_CountryCode, m_AreaCode, m_Number, m_Suffix);
    OnPropertyChanged("FullNumber");
  }

}

Then your DataTemplate becomes:

<DataTemplate x:Key="PhoneNumberTemplate">
  <StackPanel Orientation="Horizontal">
    <TextBox Text="{Binding Path=CountryCode, UpdateSourceTrigger=PropertyChanged}" />
    <TextBox Text="{Binding Path=AreaCode, UpdateSourceTrigger=PropertyChanged}" />
    <TextBox Text="{Binding Path=Number, UpdateSourceTrigger=PropertyChanged}" />
    <TextBox Text="{Binding Path=Suffix, UpdateSourceTrigger=PropertyChanged}" />
    <TextBox Text="{Binding Path=FullNumber, Mode=OneWay}" IsReadOnly="True" />
  </StackPanel>
</DataTemplate>
Julien Poulin
OK that's great, I just can't image how can I reflect the Text change in an underlying object (PhoneNumber) that is a part of a Person object somewhere deep in my Collection, when binding is specified with other elements only and not: Text="{Binding Path=PhoneNumber,Mode=TwoWay}"
PaN1C_Showt1Me
OK I'm gonna try it this way.. That's a pity that withou MVVM I cannot do some things directly in XAML...
PaN1C_Showt1Me