I have these lines of code on my XAML
<ContentPage.BindingContext>
<x:Reference Name="messagesPage" />
</ContentPage.BindingContext>
....
<Label Text="{Binding ConversationPartner.contactName[0]}" FontSize="Title" TextColor="Black"
VerticalOptions="Center" FontAttributes="Bold" HorizontalOptions="StartAndExpand">
<Label.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding ConversationPartner.contactID[1], Converter={StaticResource isViewerConverter}}" Value="False">
<Setter Property="Text" Value="{Binding ConversationPartner.contactName[1]}"/>
</DataTrigger>
</Label.Triggers>
</Label>
What I want to happen is that a name on the label represented by ConversationPartner.contactName[0] must appear on my application but it doesn't.
Here's the code behind
public partial class MessagesPage : ContentPage
{
DataClass dataClass = DataClass.GetInstance;
public ICommand CloseMsg => new Command(async () => await Navigation.PopModalAsync(true));
public ICommand SendCommand => new Command(Send);
ContactModel ConversationPartner;
public MessagesPage(ContactModel input)
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
ConversationsList = new ObservableCollection<ConversationModel>();
ConversationPartner = input;
/// some cloud firestore code here
}
}
Found a solution.
I made an observable collection so that I could bind easily.
My code behind:
public MessagesPage(ContactModel input)
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
ConversationsList = new ObservableCollection<ConversationModel>();
convoers = new ObservableCollection<string> {input.contactName[0], input.contactName[1], input.contactID[1] };
ConversationPartner = input;
...
}
then in my XAML,
<Label Text="{Binding convoers[0]}" FontSize="Title" TextColor="Black"
VerticalOptions="Center" FontAttributes="Bold" HorizontalOptions="StartAndExpand">
<Label.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding convoers[2], Converter={StaticResource isViewerConverter}}" Value="False">
<Setter Property="Text" Value="{Binding convoers[1]}"/>
</DataTrigger>
</Label.Triggers>
</Label>
Related
I want a button to change the visibility of a label once i click it.
xaml View:
<local:ButtonRenderer Text="Connect" BackgroundColor="#6DCFF6" TextColor="White" Command="{Binding viewTemperature}" CornerRadius="10" WidthRequest="200" IsVisible="{Binding !isConnecting}"/>
<Label Text="PlaceholderText" TextDecorations="Underline" TextColor="White" Margin="0,5,0,0" HorizontalTextAlignment="Center" IsVisible="{Binding !isConnecting}"/>
ViewModel
viewTemperature = new Command(async () =>
{
isConnecting = true;
await _navigation.PushModalAsync(new TemperaturePage());
}) ;
public bool isConnecting
{
get
{
return _isConnecting;
}
set
{
_isConnecting = value;
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(_isConnecting.ToString()));
}
}
I have put breakpoints in my code, and the isConnected is being changed to true in my viewmodel. However, the visibility of my label is not changed. I suspect that PropertyChanged isn't supposed to change bool values?
You cannot do IsVisible="{Binding !isConnecting}", this will not work.
You can either make a InvertBoolConverter, or, the simplier option, use Triggers. Here is a sample:
<Label Text="PlaceholderText" TextDecorations="Underline" TextColor="White" Margin="0,5,0,0" HorizontalTextAlignment="Center"
IsVisible="{Binding isConnecting}">
<Label.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding isConnecting}" Value="True">
<Setter Property="IsVisible" Value="False" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding isConnecting}" Value="False">
<Setter Property="IsVisible" Value="True" />
</DataTrigger>
</Label.Triggers>
</Label>
You can improve your code in ViewModel
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private bool isconnecting ;
public bool isConnecting
{
get
{
return isconnecting;
}
set
{
if (isconnecting != value)
{
isconnecting = value;
NotifyPropertyChanged();
}
}
}
I have a combo box that is to be filled dynamically.
When the user selects an item from the combo box, a label needs to show up.
This works when I use a static combo box, but when the combo box is dynamic it does not. I'm pretty sure it has to do with the Name field of the combo box item.
Here is the code :
C#:
public ObservableCollection<ComboBoxItem> cbItems { get; set; }
public ComboBoxItem SelectedcbItem { get; set; }
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
cbItems = new ObservableCollection<ComboBoxItem>();
var cbItem = new ComboBoxItem { Content = "<--Select-->"};
SelectedcbItem = cbItem;
cbItems.Add(cbItem);
var cbItem1 = new ComboBoxItem();
cbItem1.Content = "Option 1";
cbItem1.Name = "iOne";
var cbItem2 = new ComboBoxItem();
cbItem2.Content = "Option 2";
cbItem2.Name = "iTwo";
cbItems.Add(cbItem1);
cbItems.Add(cbItem2);
}
XAML:
<ComboBox Width="130" ItemsSource="{Binding cbItems}" SelectedItem="{Binding SelectedcbItem}" Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="2" VerticalAlignment="Bottom" HorizontalContentAlignment="Center"/>
<Label Content="One is shown" Grid.Column="0" Grid.Row="6">
<Label.Style>
<Style TargetType="Label">
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=iOne, Path=IsSelected}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
Use this XAML
<ComboBox x:Name="cb"
ItemsSource="{Binding CbItems}" SelectedItem="{Binding SelectedCbItem}" .../>
<Label Content="One is shown" ...>
<Label.Style>
<Style TargetType="Label">
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cb, Path=SelectedItem}"
Value="Option 1">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
with this code behind:
public List<string> CbItems { get; }
public string SelectedCbItem { get; set; }
public MainWindow()
{
InitializeComponent();
cbItems = new List<string> { "Option 1", "Option 2" };
DataContext = this;
}
Alternatively:
<DataTrigger Binding="{Binding ElementName=cb, Path=SelectedIndex}" Value="0">
If you want to make the DataTrigger use a Binding to the source property SelectedCbItem, like
<DataTrigger Binding="{Binding SelectedCbItem}" Value="Option 1">
that property must fire a property change notification, e.g. the PropertyChanged event of the INotifyPropertyChanged interface.
I've following code in my WPF app.I'm trying to set the focus on a textbox on a button click...i.e. on invoking Check() method...
Code:
MainWindowResources.xaml
<Style TargetType="TextBox" x:Key="MyFiedlStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=FocusOnMyField}" Value="true">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=myField}"/>
</DataTrigger>
</Style.Triggers>
</Style>
MainWindow.xaml
<TextBox HorizontalAlignment="Left" Margin="1,1,0,0" Width="180" Text="{Binding MyAttributes.MyFieldValue}" TabIndex="4" Grid.Row="3" VerticalAlignment="Top" Grid.Column="5"
Name="myField" Style="{DynamicResource MyFieldStyle}"/>
MainWindowViewModel
private bool FocusOnMyField
{
get { return m_FocusOnMyField; }
set
{
m_FocusOnMyField = value;
OnPropertyChanged("FocusOnMyField");
}
}
private void Check()
{
this.FocusOnSecDescription = true;
}
Thanks.
I have a PCL and I am using MVVM pattern.
I am building a togglebutton, that toggles when the related property in the viewmodel is activated, with behaviors and triggers.
This is my behavior
public class ToggleBehavior : Behavior<View>
{
TapGestureRecognizer tapRecognizer;
public static readonly BindableProperty IsToggledProperty = BindableProperty.Create<ToggleBehavior, bool>(tb => tb.IsToggled, false);
public bool IsToggled
{
set { SetValue(IsToggledProperty, value); }
get { return (bool)GetValue(IsToggledProperty); }
}
}
This is how I consume my behavior
<Button Text="AUTO" Style="{StaticResource SmallEllipseButton}" BackgroundColor="{StaticResource BackgroundColor}" cm:Message.Attach="Automatic($dataContext)">
<Button.Behaviors>
<local:ToggleBehavior x:Name="autoToggleBehavior" IsToggled="{Binding CurrentMode,Converter={StaticResource modeToBooleanConverter}, ConverterParameter=AUTO}"/>
</Button.Behaviors>
<Button.Triggers>
<DataTrigger TargetType="Button" Binding="{Binding Source={x:Reference autoToggleBehavior},Path=IsToggled}" Value="False" >
<Setter Property="BackgroundColor" Value="White"/>
<Setter Property="BorderColor" Value="White"/>
<Setter Property="TextColor" Value="Gray"/>
</DataTrigger>
<DataTrigger TargetType="Button" Binding="{Binding Source={x:Reference autoToggleBehavior},Path=IsToggled}" Value="True" >
<Setter Property="BackgroundColor" Value="{StaticResource BackgroundColor}"/>
<Setter Property="TextColor" Value="White"/>
</DataTrigger>
</Button.Triggers>
</Button>
The problem is that the property IsToggled is not binded correctly in this IsToggled="{Binding CurrentMode,Converter={StaticResource modeToBooleanConverter}, ConverterParameter=AUTO}"/>
If I set it statically to true or false it works.
The problem I think is that I can't bind dinamically this property.
I use the same binding with the same converter in the same page for an IsVisible property and it works.
If I put a breakpoint in the converter, the application doesn't break in it, but for the IsVisible property breaks.
Using a Button might not be the best option as it already has a tap handler and assigning one to it would still not trigger the event. I don't know if this helps but I changed the control to a Label to get the below to work. Of course if the Button is bound to a command that modifies the view model then you don't need the tap handler in the behaviour at all.
XAML:
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:BehTest" x:Class="BehTest.BehTestPage">
<Label Text="AUTO" HorizontalOptions="Center" VerticalOptions="Center">
<Label.Behaviors>
<local:ToggleBehavior x:Name="autoToggleBehavior" IsToggled="{Binding Toggled, Mode=TwoWay}"/>
</Label.Behaviors>
<Label.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding Source={x:Reference autoToggleBehavior},Path=IsToggled}" Value="False" >
<Setter Property="BackgroundColor" Value="White"/>
<Setter Property="TextColor" Value="Gray"/>
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Source={x:Reference autoToggleBehavior},Path=IsToggled}" Value="True" >
<Setter Property="BackgroundColor" Value="Blue"/>
<Setter Property="TextColor" Value="White"/>
</DataTrigger>
</Label.Triggers>
</Label>
</ContentPage>
Behaviour:
public class ToggleBehavior : Behavior<View>
{
readonly TapGestureRecognizer tapRecognizer;
public ToggleBehavior()
{
tapRecognizer = new TapGestureRecognizer
{
Command = new Command(() => this.IsToggled = !this.IsToggled)
};
}
public static readonly BindableProperty IsToggledProperty = BindableProperty.Create<ToggleBehavior, bool>(tb => tb.IsToggled, false);
public bool IsToggled
{
set { SetValue(IsToggledProperty, value); }
get { return (bool)GetValue(IsToggledProperty); }
}
protected override void OnAttachedTo(View bindable)
{
base.OnAttachedTo(bindable);
bindable.GestureRecognizers.Add(this.tapRecognizer);
}
protected override void OnDetachingFrom(View bindable)
{
base.OnDetachingFrom(bindable);
bindable.GestureRecognizers.Remove(this.tapRecognizer);
}
protected override void OnAttachedTo(BindableObject bindable)
{
base.OnAttachedTo(bindable);
this.BindingContext = bindable.BindingContext;
bindable.BindingContextChanged += Bindable_BindingContextChanged;
}
protected override void OnDetachingFrom(BindableObject bindable)
{
base.OnDetachingFrom(bindable);
this.BindingContext = null;
bindable.BindingContextChanged -= Bindable_BindingContextChanged;
}
void Bindable_BindingContextChanged(object sender, EventArgs e)
{
var bobject = sender as BindableObject;
this.BindingContext = bobject?.BindingContext;
}
}
We added a ToggleButton into our NuGet!
Its free to use.
xmlns:aw="clr-namespace:AscendantWare.Xamarin.Essentials.Controls"
<aw:AWToggleButton TextColor="White" ToggleBackgroundColor="DarkGoldenrod" Margin="0" VerticalOptions="FillAndExpand" HorizontalOptions="Fill" CornerRadius="15" IsToggled="{Binding IsNoteEnabled, Mode=TwoWay}" Command="{Binding MyCommand}"/>
More Informations in our online documentation here!
This is probably a newbie question but I’m breaking my head about this one.
I’m building an application in WPF using the MVVM pattern. I have a view which has fields binded a property exposing the current customer entity. And within the view I have a command to change the bank account numbers belonging to that customer. The command called take the whole sub-entity as parameter. Then call another function which also takes the sub-entity as parameter and passes it to a new viewmodel binded to a new view which is displayd as a dialog for change. This all works. But when I’m change the bank account number in the dialog the original view also changes the account number number real-time. They are still connected to each other. I want to cancel this link to be able to cancel the dialog and the changes I made within that dialog. But I can’t get this to work.
Code say’s more the words.
View MAIN
<dxlc:LayoutGroup Header="Rekeningen" View="GroupBox" Orientation="Vertical" VerticalAlignment="Stretch">
<dxlc:LayoutItem>
<StackPanel>
<Button Content="{x:Static language:Common.NieuwRekeningnrToevoegen}" Command="{Binding NieuwRekeningCommand}" />
<ListView ItemsSource="{Binding CurrentRelatie.Rekeningnummers}" ItemTemplate="{StaticResource RelatieRekeningnrTemplate}" />
</StackPanel>
</dxlc:LayoutItem>
</dxlc:LayoutGroup>
View item template MAIN
<DataTemplate x:Key="RelatieRekeningnrTemplate">
<Grid>
<TextBlock >
<Run Text="{Binding Omschrijving}" FontWeight="Bold" FontStyle="Italic" /> <LineBreak/>
<Run Text="{Binding RekNummer}" /> - <Run Text="{Binding BicNummer}" FontStyle="Italic" />
</TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button Command="{Binding DataContext.VerwijderRekeningCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template" Value="{DynamicResource tplFlatButton}" />
</Style>
</Button.Style>
<Path Height="9" Stretch="Uniform" Fill="{DynamicResource AccentColorDarkGray}" Data="{DynamicResource Delete}" />
</Button>
<Button Command="{Binding DataContext.EditRekeningCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template" Value="{DynamicResource tplFlatButton}" />
</Style>
</Button.Style>
<Path Height="10" Stretch="Uniform" Fill="{DynamicResource AccentColorDarkGray}" Data="{DynamicResource Edit}" >
</Path>
</Button>
</StackPanel>
</Grid>
</DataTemplate>
Viewmodel
private model.Relatie _CurrentRelatie = null;
public model.Relatie CurrentRelatie
{
get { return _CurrentRelatie; }
set { SetProperty(ref _CurrentRelatie, value, () => CurrentRelatie); }
}
public ICommand EditRekeningCommand { get; private set; }
void OnEditRekeningExecute(model.Rekeningnummer Rek)
{
EditRekeningnummer(Rek);
}
private void EditRekeningnummer(model.Rekeningnummer Rek)
{
Dialog.dRekeningnummerEditViewModel ReknummerVM = new Dialog.dRekeningnummerEditViewModel();
ReknummerVM.SetRekening(Rek);
UICommand ResCommand = DialogService.ShowDialog(ReknummerVM.DialogUICommand, string.Format("{0} {1}", Common.Rekening, Rek.Omschrijving ?? Rek.RekNummer), "viewdRekeningnummerEdit", ReknummerVM);
if (ResCommand == null || ResCommand.IsCancel == true)
return;
}
View RekeningnummerEdit
<dxlc:LayoutGroup Orientation="Vertical">
<dxlc:LayoutItem Label="{Binding CurrentRekening, ConverterParameter=Omschrijving, Converter={StaticResource ModelToDisplay}}">
<dxe:TextEdit EditValue="{Binding CurrentRekening.Omschrijving, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ValidateOnTextInput="True" utils:FocusAdvancement.AdvancesByEnterKey="true"/>
</dxlc:LayoutItem>
<dxlc:LayoutItem Label="{Binding CurrentRekening, ConverterParameter=RekNummer, Converter={StaticResource ModelToDisplay}}">
<dxe:TextEdit EditValue="{Binding CurrentRekening.RekNummer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ValidateOnTextInput="True" utils:FocusAdvancement.AdvancesByEnterKey="true"/>
</dxlc:LayoutItem>
<dxlc:LayoutItem Label="{Binding CurrentRekening, ConverterParameter=BicNummer, Converter={StaticResource ModelToDisplay}}">
<dxe:TextEdit EditValue="{Binding CurrentRekening.BicNummer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ValidateOnTextInput="True" utils:FocusAdvancement.AdvancesByEnterKey="true"/>
</dxlc:LayoutItem>
</dxlc:LayoutGroup>
Viewmodel RekeningnummerEdit
public dRekeningnummerEditViewModel()
{
DialogUICommand = new List<UICommand>();
AnnuleerUICommand = new UICommand() {
Caption=Common.Annuleren,
Id = MessageBoxResult.Cancel,
IsCancel=true
};
OKUICommand = new UICommand() {
Caption=Common.Opslaan,
Id = MessageBoxResult.OK,
IsDefault=true
};
DialogUICommand.Add(OKUICommand);
DialogUICommand.Add(AnnuleerUICommand);
CurrentRekening = new model.Rekeningnummer();
}
public void SetRekening(model.Rekeningnummer Rek)
{
CurrentRekening = Rek;
IsInEditMode = true;
}
#region "Properties"
private model.Rekeningnummer _CurrentRekening;
public model.Rekeningnummer CurrentRekening
{
get { return _CurrentRekening; }
set { SetProperty(ref _CurrentRekening, value, () => CurrentRekening); }
}
#endregion
#region "Private function"
#endregion
#region "Commands"
public List<UICommand> DialogUICommand { get; private set; }
protected UICommand AnnuleerUICommand { get; private set; }
protected UICommand OKUICommand { get; private set; }
The behaviour you're seeing is because you are passing an object reference (model.Rek) from your view to your dialog. Therefore when your dialog changes the values of the model.Rek, the changes are immediately reflected in your view.
A common approach to solve this problem is to:
Clone (copy) your model, i.e. make a new object with the same values. You can use the ICloneable interface as a standard pattern (MemberwiseClone can help here if you only need a shallow copy)
Send the clone to your dialog
If the user presses OK, then take the values of the clone and copy them back to the original model. If the user presses Cancel, then do nothing more