It is possible to add multiple bindings to a Label using XAML?

joaobp7joaobp7 BRMember ✭✭

It is possible to add multiple Bindings to a Label using XAML, for example:

<Label Text = "{Binding Address} - {Binding City} / {Binding State}" TextColor = "# ffeece"/>

Best Answer

Answers

  • NMackayNMackay GBInsider, University mod

    @joaobp7

    No, pass the object to a value converter and get it to compose the string or another approach is to wrap your object to bind in a presentation object which as properties for view specific display of data, that way you don't add display only properties to you data object.

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    string.format

    But It might be better to overide ToString on your model so the string representative of the thing is how you want it to appear.

  • joaobp7joaobp7 BRMember ✭✭

    @NMackay
    Hi Norman, Would you have an example of how to do this?

  • NMackayNMackay GBInsider, University mod

    @joaobp7

    I'd need to knock up a sample but it's pretty straightforward. If your struggling to get it implemented then get back to me but have a go 1st in a sample app.

  • joaobp7joaobp7 BRMember ✭✭

    Thank you Alessandro!

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    If you're going to do that, you might as well just override ToString on the model - and not have to know the property name in XAML at all.

    Besides, you shouldn't add properties to model for the sole purpose of UI. That's bad practice. Its fast and lots of people do it. But it doesn't make it right.
    You can use string.format in XAML. Since this is strictly a UI need, it should be a strict UI implementation.

    Of course, you could do better XAML and have a label for each part of the address, binded back to the individual properties of the address object. Instead of trying hack a single label to show everything. It would be a 'more right' approach and every label would update in real-time... each part could be dealt with individually such as having the state be a different color, or go through a converter to abbreviate. You have to think long-term and new features and wishes that will be asked for a year from now.

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    @ClintStLaurent how can you use string.Format in the binding with 3 different fields?

  • NMackayNMackay GBInsider, University mod

    My suggestion was to have a binding object and have the raw data object as a property, there's nothing wrong with that approach.

    I wasn't aware you can bind multiple properties and use string format in a binding, I don't think that is possible.

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    Hmm... I use string.format in xaml frequently. But always for one thing. Now I'm curious. Have to go experiment.

  • NMackayNMackay GBInsider, University mod

    String format will work with one property, I do that all the time.

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    Multiple binding is not possible. Maybe in the future. Could be a very useful option

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    WPF XAML has multibinding so we would normally do this:

    <TextBlock>
        <TextBlock.Text>
            <MultiBinding StringFormat="{}{0:F1}{1:F1}">
                <Binding Path="A" />
                <Binding Path="B" />
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock>
    

    But Xamarin doesn't have multibinding out of the box. So I tried a couple things:

    <Label Text="{Binding AppVM.CurrentTruck.ID, StringFormat='#{0}'}" />
    Displays correctly as: >#12345

    <Label Text="{Binding AppVM.CurrentTruck.ID, AppVM.CurrentTruck.Trailer.ID, StringFormat='#{0}.{1}'}"/>
    Doesn't raise a design-time complaint but does error:

    04-26 11:14:09.497 I/MonoDroid(28940): System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.

    But... It tried. It saw the {1} and tried to do something with it. That's a good sign. It tried to find the 1th indexed element. It failed and exceptioned. But it tried.

    Since we do implement our own multibinding class, the closest I see is to do that via a multibinding converter.

                <!--#region Driver Time-->
                <Label HorizontalOptions="End"
                       BindingContext="{x:Reference this}">
                    <Label.Text>
                        <converters:MultiBinding Converter="{StaticResource ToDriverTimeStringConverter}">
                            <Binding Path="AppVM.LocalTime" />
                            <Binding Path="AppVM.LocalTimeZoneInfo" />
                            <Binding Path="AppVM.DesiredTimeZone" />
                        </converters:MultiBinding>
                    </Label.Text>
                </Label>
                <!--#endregion Driver Time-->
    

    Which takes the multiple bindings then calculates the time for a the time zone then spits out

    1745 EST

    There are multibinding classes for Xamarin floating around the 'net. I'm sure a little RnD could results in a multibinded string.formatter of some kind. But its not my project and play time (IE: Lunch time) is over.

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    I think a possibility is to use a IValueConverter. For Example, if your Binding is something like

    "{Binding .}"
    

    then you can use a IValueConverter that convert your "MyModel" to a String

        public class ModelToStringConverter : IValueConverter
            {
    
                #region IValueConverter implementation
    
                public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
                {
                    if (value is MyModel && value != null)  {
    
                MyModel tmp = (MyModel)value;
                        return string.Format("{0} - {1} / {2}",  tmp.Address, tmp.City,  tmp.State);
                    }
                    return "**-**/**";
                }
    
                public object ConvertBack (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
                {
                    throw new NotImplementedException ();
                }
    
                #endregion
            }
    

    Not tested, but should do something

  • CodeGrueCodeGrue USMember ✭✭
    edited February 2018

    Another way to do this without using a custom property on your model (mixing data with presentation) or building a custom converter (overkill) is just use a StackLayout:

    <StackLayout Orientation="Horizontal">
        <Label Text="{Binding Address, StringFormat='{0}'}" TextColor="#ffeece" />                                                  
        <Label Text="{Binding City, StringFormat=' - {0}'}" TextColor="#ffeece" />  
        <Label Text="{Binding State, StringFormat=' / {0}'}" TextColor="#ffeece" />                                                                                                          
    </StackLayout>
    
  • sonic1015sonic1015 CAMember ✭✭

    @CodeGrue said:
    Another way to do this without using a custom property on your model (mixing data with presentation) or building a custom converter (overkill) is just use a StackLayout:

    <StackLayout Orientation="Horizontal">
        <Label Text="{Binding Address, StringFormat='{0}'}" TextColor="#ffeece" />                                                  
        <Label Text="{Binding City, StringFormat=' - {0}'}" TextColor="#ffeece" />  
        <Label Text="{Binding State, StringFormat=' / {0}'}" TextColor="#ffeece" />                                                                                                          
    </StackLayout>
    

    Problem with this is that there won't be any line wrap.

  • prishahprishah CAMember ✭✭

    Why to make complicated code as xamarin forms provide amazing stack layout , I have achieved my multiple labels by using multiple stacklayout and set orientation property according to my project needs. Here is the example :

    <StackLayout Orientation="Horizontal">
             <!--<Image Source="" />-->
                 <StackLayout Orientation="Vertical">
                                <StackLayout Orientation="Horizontal">
                                    <Label Text="Job Number : " FontAttributes="Bold" FontSize="20" />
                                    <Label Text="{Binding JobNum}" FontAttributes="Bold" FontSize="20" />
                                </StackLayout>
                       <Label Text="{Binding Company}" FontSize="15" FontAttributes="Bold"/>
                       <Label Text="{Binding Project}" FontSize="15" FontAttributes="Bold"/>
                       <Label Text="{Binding Lot}" FontSize="15" FontAttributes="Bold"/>
                 </StackLayout>
     </StackLayout>
    
  • prishahprishah CAMember ✭✭
    edited March 2018

    @ClintStLaurent said:
    That's fine if you want a stack. But as sonic pointed out, it won't make a continuous flowing single paragraph.

    Personally I think its just easier to put multiple Spans in the Label. Its XAML, they're bindable, they can be formatted individually etc.

      <Label FontSize=20>
        <Label.FormattedText>
          <FormattedString>
            <Span Text="{Binding FirstName}" ForegroundColor="Red" FontAttributes="Bold" />
            <Span Text="{Binding MI}" />
            <Span Text="{Binding LastName}" FontAttributes="Italic" FontSize="Small" />
          </FormattedString>
        </Label.FormattedText>
      </Label>
    

    @ClintStLaurent When I use your above code , it seems not working on my project, throwing error :
    No property, bindable property, or event found for 'Text', or mismatching type between value and property.

    My code is below :

  • prishahprishah CAMember ✭✭
    edited March 2018
                    <Label FontSize="15">
                                    <Label.FormattedText>
                                        <FormattedString>
                                            <Span Text="{Binding Company}" ForegroundColor="Red" FontAttributes="Bold" />
                                            <Span Text="{Binding Project}" />
                                            <Span Text="{Binding Lot}" FontAttributes="Italic" FontSize="Small" />
                                        </FormattedString>
                                    </Label.FormattedText>
                                </Label>
    
  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    Hmmm... That's copied from an OLD project. Maybe it no longer works. Let me try it on something more recent

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    @prishah
    This is from a new project. Looks like they added a subsection of .Spans to the XAML specification.

                    <Label FontSize="22">
                        <Label.FormattedText>
                            <FormattedString>
                                <FormattedString.Spans>
                                    <Span FontAttributes="Bold"
                                          FontSize="22"
                                          Text="First span. " />
                                    <Span FontAttributes="Italic"
                                          FontSize="22"
                                          Text="Another span in italic. " />
                                    <Span FontAttributes="Bold"
                                          FontSize="12"
                                          Text="This one is smaller" />
                                </FormattedString.Spans>
                            </FormattedString>
                        </Label.FormattedText>
                    </Label>
    
  • prishahprishah CAMember ✭✭

    @ClintStLaurent said:
    @prishah
    This is from a new project. Looks like they added a subsection of .Spans to the XAML specification.

                    <Label FontSize="22">
                        <Label.FormattedText>
                            <FormattedString>
                                <FormattedString.Spans>
                                    <Span FontAttributes="Bold"
                                          FontSize="22"
                                          Text="First span. " />
                                    <Span FontAttributes="Italic"
                                          FontSize="22"
                                          Text="Another span in italic. " />
                                    <Span FontAttributes="Bold"
                                          FontSize="12"
                                          Text="This one is smaller" />
                                </FormattedString.Spans>
                            </FormattedString>
                        </Label.FormattedText>
                    </Label>
    

    @ClintStLaurent I still have an error , it keeps complaining about

    "Type FormattedString.Spans not found in xmlns http://xamarin.com/schemas/2014/forms"

    Below is my code :

        <Label FontSize="14">
                                        <Label.FormattedText>
                                            <FormattedString>
                                                <FormattedString.Spans>
                                                    <Span Text="{Binding Company}" FontAttributes="Bold" />
                                                    <Span Text="{Binding Project}" FontAttributes="Bold" />
                                                    <Span Text="{Binding Lot}" FontAttributes="Bold" />
                                                </FormattedString.Spans>
                                            </FormattedString>
                                        </Label.FormattedText>
                                    </Label>
    
  • robertfribergrobertfriberg Member ✭✭

    @prishah @ClintStLaurent Span.Text does not support binding, thus the exception "No property, bindable property, or event found for 'Text', or mismatching type between value and property."

  • robertfribergrobertfriberg Member ✭✭

    Bindable span is available from Xamarin Forms version 3.1.0-pre, see https://forums.xamarin.com/discussion/96456/bindable-span

  • teapengteapeng USMember ✭✭

    @AlessandroCaliaro said:
    I think a possibility is to use a IValueConverter. For Example, if your Binding is something like

    "{Binding .}"

    then you can use a IValueConverter that convert your "MyModel" to a String

    public class ModelToStringConverter : IValueConverter
    {

    #region IValueConverter implementation

    public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
    if (value is MyModel && value != null) {

    MyModel tmp = (MyModel)value;
    return string.Format("{0} - {1} / {2}", tmp.Address, tmp.City, tmp.State);
    }
    return "-/**";
    }

    public object ConvertBack (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
    throw new NotImplementedException ();
    }

    #endregion
    }

    Not tested, but should do something

    Cool, the Binding "." dot is exactly what I have been searching all over the place of passing the whole object into the converter. This will be very handy and can do anything. Thanks!

  • Esaavedra89Esaavedra89 USMember ✭✭

    @AlessandroCaliaro said:

    public string NewProperty{

      get {
          return string.Format("{0} - {1} / {2}",  Address, City,  State);
      }
    

    }

    Easy solution, thanks!

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    @Esaavedra89 said:

    @AlessandroCaliaro said:

    public string NewProperty{
    
        get {
            return string.Format("{0} - {1} / {2}",  Address, City,  State);
        }
    }
    
    
    <Label Text = "{Binding NewProperty}" TextColor = "# ffeece"/>
    

    Easy solution, thanks!

    The problem I have with that is that the ViewModel now makes new properties for the sole purpose of how string are to be displayed. That's rather... dirty... anti-MVVM.

    The ViewModel really should only have the data: Address, city, State and not care or know anything about how it is displayed. That's the responsibility of the UI. Otherwise imagine what you'd have if the same ViewModel were the backing (binding context) for 25 different views... and you had 10 different ways that same data should be displayed depending on the form, or view, or report. You don't need 250 custom properties in the ViewModel just for formatting.

    If you format the display in the display you don't have these problems.

Sign In or Register to comment.