How Binding between string[] and some Labels controls?

Elad770

Member
Joined
Oct 4, 2021
Messages
20
Programming Experience
1-3
Hello
I am trying to bind between a property of a string array and some Label defined in xaml.
I'm just like that:
C#:
//ViewModel
 public  class User
 {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string Id { get; set; }
        public bool IsVisable { get; set; }
        public string[] Massages { get; set; }

        public User()
        {
            Massages  = new string[3];
        }
  }

//code behind
 public MainWindow()
 {
        
            InitializeComponent();
            DataContext = new User()
            {
                UserName = "blbla",
                Password = "AAA000YYSS",
                Id = "123123098S",
                Massages = new string[]{"UserName invalid","Password  invalid","Id  invalid"}
            };
 }

//xaml
<Window>
 <Grid Name="grid" HorizontalAlignment="Center" Margin="0,50,0,0">
   <Grid.RowDefinitions>
        <!--0-->
        <RowDefinition Height="110"/>
        <!--1-->
        <RowDefinition Height="40"/>
        <!--2-->
        <RowDefinition Height="30"/>
        <!--3-->
        <RowDefinition Height="30"/>
        <!--4-->
        <RowDefinition Height="auto" />
        <!--5-->
        <RowDefinition Height="30"/>
        <!--6-->
        <RowDefinition Height="30"/>
        <!--7-->
        <RowDefinition Height="auto" />
        <!--8-->
        <RowDefinition Height="30"/>
        <!--9-->
        <RowDefinition Height="30"/>
        <!--10-->
        <RowDefinition Height="auto" />
        <!--11-->
        <RowDefinition Height="8"/>
        <RowDefinition Height="41"/>
        <RowDefinition/>
   </Grid.RowDefinitions>
   <Grid.ColumnDefinitions>
     <ColumnDefinition Width="auto"/>
   </Grid.ColumnDefinitions>
   <TextBlock Name="titleLogin" Grid.Row="1" Text="Login" Foreground="#FF7A7171" FontSize="23" FontWeight="Bold"  HorizontalAlignment="Center"/>
   <TextBlock Name="lUserName" FontWeight="Bold" Grid.Column="1" Grid.Row="2" Text="User Name" Foreground="#FF7A7171" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
   <TextBox   x:Name="txtUsername" Height="30" Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource }"    Grid.Row="3" Style="{DynamicResource textboxPasswordboxStyles}"   Width="290"    />
   <!--Binding Massages[0] not working-->
   <Label Name="massageErrorUserName"  Grid.Row="4"  Grid.Column="1" FontSize="14" Foreground="Red"  Content="{Binding Massages[0], Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />
   <TextBlock Text="Password"  Grid.Row="5" HorizontalAlignment="Center" VerticalAlignment="Bottom" FontWeight="Bold"  Foreground="#FF7A7171" />
   <PasswordBox x:Name="txtPassword" PasswordChanged="txtPassword_PasswordChanged"  Style="{DynamicResource textboxPasswordboxStyles}"  Height="{Binding ElementName=txtUsername, Path=Height}"  Grid.Column="1"   Width="{Binding ElementName=txtUsername, Path=Width}"   Grid.Row="6" />
   <!--Binding Massages[1] not working-->
   <Label Name="massageErrorPassword"  Grid.Row="7" Foreground="Red"   Grid.Column="1" FontSize="14" Content="{Binding user.Massages[1], Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />
   <TextBlock Text="ID" FontWeight="Bold"  Grid.Row="8" HorizontalAlignment="Center" VerticalAlignment="Bottom"  Foreground="#FF7A7171" />
   <TextBox x:Name="txtId" Text="{Binding Id, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource }" Height="{Binding ElementName=txtUsername, Path=Height}"  Style="{DynamicResource textboxPasswordboxStyles}" FontSize="21"  Width="{Binding ElementName=txtUsername, Path=Width}"  Grid.Row="9" />
   <!--Binding Massages[2] not working-->
   <Label Name="massageErrorId" Grid.Row="10" Grid.Column="1" FontSize="14" Foreground="Red"  Content="{Binding Massages[2], Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />
   <Label Name="massageError"    Visibility="{Binding IsVisable,
                                 Converter={StaticResource BooleanToVisibilityConverter}}"  Content="The user is not registered"  Grid.Row="10" Grid.Column="1" FontSize="14"  Foreground="Red"  />
   <Button x:Name="btn" Content="Login" FontSize="18"  Grid.Row="12"   Style="{StaticResource btn-primary}"  Click="Btn_Click"    />
 </Grid>
</Window>
the binding not working with string[], all the rest of the properties work great.
By the way I do not inherit INotifyPropertyChanged because I use with a package from Nuget called Fody that saves the writing of the PropertyChangedEventHandler event and writing on all properties
 
Last edited:
The simplest approach is just create another property that exposes that array element and bind to that property instead of trying to create a binding path that goes into the array. Trynig to bind into an array breaks "The Law of Demeter".
 
The simplest approach is just create another property that exposes that array element and bind to that property instead of trying to create a binding path that goes into the array. Trynig to bind into an array breaks "The Law of Demeter".
I checked the array with the binding works in running the program but
No matter which way I do (even as you suggested) for some reason
The Binding does not work when I change the contents of the array (which I press the button and enter other contents in the boxes)
This setting UpdateSourceTrigger = PropertyChanged does not work.
 
Well, since you didn't implement INotifyPropertyChanged yourself and are dependent on that Fody Nuget package, are you sure that Fody knows how to deal with things when they look something like this:
C#:
class Foo
{
    public string [] MyArray { get; set; }
    public string MyArrayElement0
    {
        get => MyArray[0];
        set => MyArray[0] = value;
    }
}
 
Well, since you didn't implement INotifyPropertyChanged yourself and are dependent on that Fody Nuget package, are you sure that Fody knows how to deal with things when they look something like this:
C#:
class Foo
{
    public string [] MyArray { get; set; }
    public string MyArrayElement0
    {
        get => MyArray[0];
        set => MyArray[0] = value;
    }
}
Yes you are right in this section it should not work and must implement the interface and yet it still does not work

There is a situation where my implementation is a bit problematic in the first place (I am not talking about the array itself), I did not mention it at first because I thought it was a pretty marginal matter but basically I have a UserControl window that actually contains the text boxes and button, there is the User class with which I Does the binding and there is another window regardless of them to which I add this UserContorl and in fact when I click on this button I run an EventHandler event with which I actually run a function that is in the window, beyond this function I perform validations on the contents of the boxes and change the array Of the string accordingly and then the program returns to that EventHandler event and I checked with the debugger that actually the content itself of the labels is still empty.
I do not know how to solve this?
 
I click on this button I run an EventHandler event with which I actually run a function that is in the window
So you are doing data binding the recommended WPF/MVVM way, but you are not doing command handling/binding the recommended WPF/MVVM way? Strange.
 
I do not know how to solve this?
Yes. You have to ensure 2 things:
1) That you are talking to the same view model object instance in your event handler that is bound to the WPF UI;
2) Ensure that all the property change notifications are sent to the WPF UI.
 
So you are doing data binding the recommended WPF/MVVM way, but you are not doing command handling/binding the recommended WPF/MVVM way? Strange
Unfortunately I did not really get to work with MVVM, although apparently it seems so.
Regarding the two things you mentioned.
1 yes, this is exactly the same instance, UserControl gets the instance of User through the same window running in the background
Regarding 2, the content of the array varies of course but if you mean it triggers the event?
PropertyChangedEventHandler defined in this class gives the impression that the event is not triggered when a value in the array changes (I just check this with the debugger and break point not coming).
Regarding the changes to the text boxes I see that the event is triggered with each change.
I basically have a relatively simple solution
C#:
 //UserControl
private void Btn_Click(object sender, RoutedEventArgs e)
{
         this.UserControlClicked?.Invoke(sender, e);
         var labels = gridScoend.Children.OfType<Label>().ToList();
         for (int i = 0; i < labels.Count -1; i++)
         {
              labels[i].Content = user.Massages[i];
              //show label or  Collapsed it
              labels[i].Visibility = user.Massages[i] != "" ? Visibility.Visible : Visibility.Collapsed;
         }

}
but in practice it is not binding And I want to solve it the right way.
 
Last edited:
Okay, the solution is probably like you said at the beginning not to use with an array of strings (although I do not understand the principle you explained at the beginning with a diameter). But actually split it into variables or use with a special list of wpf
 
Back
Top Bottom