How a user select to display 1 out of two (or more) fields on a single Label in Xamarin

65 Views Asked by At

I'm trying to use a single Label to display one of the two data fields alternately in Xamarin Forms. Only Label 1 Displaying the binding field (Contact_Name), while second Label which I am trying to use a variable "DisplayField" is not displaying either 'Contact_Address' or 'Contact_eMail' . Question posted before and Another user tried to help but it didn't work!

Model Class

public class Contacts
{
  [PrimaryKey][Autoincrement]
  public int Contact_ID { get; set; }
  public string Contact_Name { get; set; }
  public string Contact_Address { get; set; }
  public string Contact_eMail { get; set; }
}

XAML Page

  <StackLayout>
    <Button Text="Display Address" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Fill" Clicked="Display_Address" />
    <Button Text="Display Email" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Fill" Clicked="Display_eMail" />
    <Entry HorizontalOptions="FillAndExpand" Text="{Binding DisplayField}" />
    <ListView x:Name="listView" HasUnevenRows="True" >
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell >
                    <StackLayout Orientation="Vertical" VerticalOptions="CenterAndExpand" >
                        <Frame >
                            <StackLayout Orientation="Vertical" VerticalOptions="Center">
                                <Label Text="{Binding Contact_Name}" FontSize="Medium" LineBreakMode="WordWrap" />
                                <Label Text="{Binding DisplayField}" LineBreakMode="WordWrap" />
                            </StackLayout>
                        </Frame>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

Code Behind

 public partial class FieldSwap : ContentPage
 {
readonly FieldViewModel _fieldViewModel;
readonly SQLiteAsyncConnection _connection = DependencyService.Get<ISQLite>().GetConnection();
public ObservableCollection<Contacts> CList { get; set; }
public static string DisplayField { get; private set; }

public static int caseSwitch { get; private set; }

public FieldSwap()
{
    InitializeComponent();
    _fieldViewModel = new FieldViewModel();
    _fieldViewModel.Field = "Contact_Address";
    
    this.BindingContext = _fieldViewModel;
}

   public static void SelectField()
   {
    

       switch (caseSwitch)
       {
         case 1:
            DisplayField = "Contact_Address";
            break;

        case 2:
            DisplayField = "Contact_eMail";
            break;

        default:
            DisplayField = ("Contact_Address");
            break;
      }
   }

   private void Display_Address(object sender, EventArgs e)
   {
    caseSwitch = 1;
    SelectField();
    ReadData();
   }

   private void Display_eMail(object sender, EventArgs e)
   {
    caseSwitch = 2;
    SelectField();
    ReadData();
   }

   public void ReadData()
   {
     var list = _connection.Table<Contacts>().ToListAsync().Result;
     CList = new ObservableCollection<Contacts>(list);
     listView.ItemsSource = CList;
   }
}

View Model Class

 public class FieldViewModel : INotifyPropertyChanged
 {
 public event PropertyChangedEventHandler PropertyChanged;

 String _field;

 public string Field
 {
    set
    {
        if (!value.Equals(_field, StringComparison.Ordinal))
        {
            _field = value;
            OnPropertyChanged("DisplayField");
        }
    }
    get
    {
        return _field;
    }
  }
  void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    PropertyChanged?.Invoke(this, new 
    PropertyChangedEventArgs(propertyName));
  }
 }
1

There are 1 best solutions below

1
On BEST ANSWER

You could use IsVisible property to achieve that, not need to bind only one lable.

Therefore, binding Contact_Address and Contact_eMail with two lables in StackLayout as follows:

<StackLayout Orientation="Vertical" VerticalOptions="Center">
     <Label Text="{Binding Contact_Name}" FontSize="Medium" LineBreakMode="WordWrap" />
     <Label Text="{Binding Contact_Address}" IsVisible="{Binding AddressVisible}" LineBreakMode="WordWrap" />
     <Label Text="{Binding Contact_eMail}" IsVisible="{Binding EMailVisible}" LineBreakMode="WordWrap" />
</StackLayout>

Then in Contacts add two visiable proerty:

public class Contacts: INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    ...

    private bool addressVisible;
    public bool AddressVisible
    {
        set
        {
            if (addressVisible != value)
            {
                addressVisible = value;
                OnPropertyChanged("AddressVisible");
            }
        }
        get
        {
            return addressVisible;
        }
    }

    private bool eMailVisible;
    public bool EMailVisible
    {
        set
        {
            if (eMailVisible != value)
            {
                eMailVisible = value;
                OnPropertyChanged("EMailVisible");
            }
        }
        get
        {
            return eMailVisible;
        }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

}

Now in Contentpage, you could modify the visiable propery when button be clicked:

private void Display_Address(object sender, EventArgs e)
{
    foreach(var item in CList )
    {
        item.AddressVisible = true;
        item.EMailVisible = false;
    }
}

private void Display_eMail(object sender, EventArgs e)
{
    foreach (var item in CList )
    {
        item.AddressVisible = false;
        item.EMailVisible = true;
    }
}

Here is the effect:

enter image description here