All My data photo is in server Example url: http://abcd.com/images/ and i have renamed all the photos file to my album id example 1.jpg,2.jpg
and i want to display those photos using albumid in grid view
class AlbumData
{
public Int32 AlbumId { get; set; }
public String Name { get; set; }
public String Language { get; set; }
public String Actors { get; set; }
public String Director { get; set; }
public String MusicDirector { get; set; }
public String Year { get; set; }
}
private void Search_Click(object sender, RoutedEventArgs e)
{
WebClient webclient = new WebClient();
webclient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webclient_DownloadStringCompleted);
webclient.DownloadStringAsync(new Uri("http://albums.abcd.com/v1/Albums/English/1"));//--getting data using xml
}
void webclient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show("error");
}
XElement XmlTweet = XElement.Parse(e.Result);
listBox1.ItemsSource = from tweet in XmlTweet.Descendants("Album")
select new AlbumData()
{
Name = tweet.Element("Name").Value,
//--how to display image---//
};
}
Please help me with example
<DataTemplate>
<StackPanel>
<Image Source="{Binding ImageSource}" Height="100" Width="100" HorizontalAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="{Binding Name}" Foreground="#FFC8AB14" FontSize="15" Width="120" TextAlignment="Center" TextWrapping="Wrap" />
<!--<TextBlock Text="{Binding Message}" TextWrapping="Wrap" FontSize="8" Width="100" TextAlignment="Center" />-->
<!--<TextBlock Text="{Binding MusicDirector}" TextWrapping="Wrap" FontSize="8" Width="100" TextAlignment="Center" />-->
<!--<TextBlock Text="{Binding UserName}" Style="{StaticResource PhoneTextSubtleStyle}" Width="100" TextAlignment="Center"/>-->
</StackPanel>
</DataTemplate>
Assuming the ElementName of your images is ImageUri, you must change your ItemsSource to:
listBox1.ItemsSource =
from tweet in XmlTweet.Descendants("Album")
select new AlbumData()
{
Name = tweet.Element("Name").Value,
ImageSource = new BitmapImage(new Uri(tweet.Element("ImageUri"), UriKind.Relative));
};
AlbumData needs to be extended by
public BitmapImage ImageSource { get; set; }
Related
All the fields show ok, only Specilities string[] shows me an error... remember there are two different fids on json response we have Speciality that is OK and show OK... and we have Specilities string[] where is the problem.... check the json response
this is json response
{"_id":"5aab4c02f08d9324fc1283ec","firstName":"Carlos Alberto","lastName":"Cabezas Delgado","password":"$2a$10$BuYWhiMn.9RsBKJN7bWuguKaPAHQocd2eVQCqRaaAdmzrlPkuWYJS","identificationNumber":"0914891684","email":"carlos.cabezas#abogadosecuador.com.ec","phone":"0969922421","discount":0.5,"band":3,"city":"59cda262fe728437ce90ff81","role":"59cd270f07308946e6a494f7","__v":6,
"speciality":{"_id":"5a0a6176257e970afc9a9e7f","name":"Propiedad Intelectual","tag":"propiedad-intelectual","__v":0,"icon":"speciality_icon_jg4zpoeqoiwtuuy8jya.png","description":"Derechos de propiedad industrial, derechos de autor, patentes, modelos de utilidad, diseños industriales, marcas, indicaciones geográficas, información comercial confidencial, derecho de obtentor.","id":"5a0a6176257e970afc9a9e7f"},
"profile":"5aac7b42c02ece25becefd47","telephone":"593969922421","createdAt":"2018-08-20T03:07:03.838Z","searchTag":"CARLOSALBERTOCABEZASDELGADO","updatedAt":"2020-06-22T00:17:30.971Z","label":"CARLOS ALBERTO CABEZAS DELGADO","firstNameLabel":"Carlos Alberto","lastNameLabel":"Cabezas Delgado","plan":"5d75e792184bab2c72b3d3ab","seller":"5ad72ce8fd69e7aba867c118","telephone2":"","fax":"593969922421","isPublic":true,"isDelete":false,
"invoices":[],
"specialities":["5990d7273da48f4bd98c6918","5990d73f3da48f4bd98c691a","5a0a6055257e970afc9a9e70","5a0a6087257e970afc9a9e73","5a0a6120257e970afc9a9e7a","5a0a6166257e970afc9a9e7e","5a0a6176257e970afc9a9e7f"],
"location":{"address":"Urbanización Puerto Azul, Guayaquil, Ecuador","reference":"Puerto Azul, Vía la Costa (Edificio Torres del Edén)","latitude":-2.1902934315119,"longitude":-79.9647494058045},"status":2,"id":"5aab4c02f08d9324fc1283ec","search":"CARLOS ALBERTO CABEZAS DELGADO"
MODEL DATA
namespace App1
{
public class AbogadosMongoApi
{
[JsonProperty("_id")]
public string Idab { get; set; }
[JsonProperty("label")]
public string FirtsName { get; set; }
[JsonProperty("email")]
public string Correo { get; set; }
[JsonProperty("phone")]
public string Celular { get; set; }
[JsonProperty("password")]
public string Contrasena { get; set; }
[JsonProperty("isPublic")]
public bool Public { get; set; }
[JsonProperty("band")]
public int Band { get; set; }
[JsonProperty("plan")]
public string Plan { get; set; }
[JsonProperty("city")]
public string Ciudadperfil { get; set; }
[JsonProperty("location")]
public Location location { get; set; }
[JsonProperty("speciality")]
public Speciality speciality { get; set; }
[JsonProperty("specialities")]
public string[] Specialities { get; set; }
}
public class Speciality
{
[JsonProperty("_id")]
public string Idespecialidad { get; set; }
[JsonProperty("name")]
public string Nombrespecialidad { get; set; }
[JsonProperty("icon")]
public string Iconespecialidad { get; set; }
[JsonProperty("description")]
public string Descespecialidad { get; set; }
}
public class Location
{
[JsonProperty("address")]
public string Direccion { get; set; }
[JsonProperty("reference")]
public string Referencia { get; set; }
[JsonProperty("latitude")]
public string Latitud { get; set; }
[JsonProperty("longitude")]
public string Longitud { get; set; }
}
}
XAML
<CollectionView x:Name="abogadosrec"
BackgroundColor="#eee"
SelectionMode="Single"
SelectionChanged="CallBtnClicked"
VerticalOptions="StartAndExpand"
HorizontalOptions="CenterAndExpand">
<CollectionView.ItemTemplate>
<DataTemplate>
<SwipeView>
<SwipeView.LeftItems>
<SwipeItems>
</SwipeItems>
</SwipeView.LeftItems>
<SwipeView.RightItems>
<SwipeItems>
<SwipeItem Text="Crear Cita"
BackgroundColor="#00a783" />
</SwipeItems>
</SwipeView.RightItems>
<Grid Style="{StaticResource IndicatorLabelStyle}"
Padding="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Frame CornerRadius="100"
HeightRequest="75"
WidthRequest="75"
BorderColor="#cca876"
HorizontalOptions="Center"
Padding="0"
IsClippedToBounds="True">
<Image xct:TouchEffect.PressedScale="1.4"
Grid.RowSpan="2"
Source="{Binding Idab, StringFormat='https://abogadosecuador.com.ec/profile/picture/{0:N}'}"
Aspect="AspectFill"
HeightRequest="75"
WidthRequest="75" />
</Frame>
<Label Grid.Column="1"
Text="{Binding FirtsName}"
VerticalOptions="CenterAndExpand"
HorizontalOptions="StartAndExpand"
FontSize="Micro"
FontAttributes="Bold" />
<ListView ItemsSource="{Binding .}"
HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label FontSize="3" Text="{Binding Specialities}"></Label>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Label Grid.Column="1"
x:Name="txtNumero" IsVisible="false"
Text="{Binding Celular, Mode=TwoWay}"
FontAttributes="Italic"
VerticalOptions="CenterAndExpand"
HorizontalOptions="StartAndExpand" />
</Grid>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.Header>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Padding="10"
Text="Abogados Registrados"
FontSize="Small" />
</StackLayout>
</CollectionView.Header>
</CollectionView>
this
<ListView ItemsSource="{Binding .}"
should be
<ListView ItemsSource="{Binding Specialities}"
and this
<Label FontSize="3" Text="{Binding Specialities}" />
should be
<Label FontSize="3" Text="{Binding .}" />
In my Xamarin Forms app Home.xaml are not displaying the image back after saving in database. While debugging I could see, bytes[] are displaying at PlayerImage against the player. In the xaml, I have Source="{Binding PlayerImage}" but couldn't figure the reason for not displaying. Are the bytes displaying correct at the break point ?
// Home.xaml
<ContentPage.Resources>
<DataTemplate x:Key="playerTemplate">
<ContentView>
<StackLayout Margin="5,5" BackgroundColor="#584961">
<Image x:Name="{PlayerImage}" Source="{Binding PlayerImage}" WidthRequest="25" HeightRequest="25"/>
<Label Text="{Binding FullName}" Font="Bold,18" TextColor="White"/>
<Label Text="{Binding Mobile}" Font="Bold,13" TextColor="White"/>
<Label Text="{Binding SoccerPosition}" Font="Bold,13" TextColor="White"/>
<Button Text="Remove Player" Clicked="DeleteButton_OnClicked" WidthRequest="120" HeightRequest="50" TextColor="White" BackgroundColor="#d6b947"></Button>
</StackLayout>
</ContentView>
</DataTemplate>
</ContentPage.Resources>
<StackLayout Margin="5">
<CollectionView x:Name="collectionview"
ItemTemplate="{StaticResource playerTemplate}">
<!--span here decides the number of items shows in one line. Now is 3 items one line-->
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="3" />
</CollectionView.ItemsLayout>
</CollectionView>
</StackLayout>
// PlayerDetails.cs
public byte[] PlayerImage { get; set; }
//Home.xaml.cs
public void DisplayDetails()
{
List<PlayerDetails> details = (from x in conn.Table<PlayerDetails>() select x).ToList();
for (int i = 0; i < details.Count; i++)
{
players.Add(details[i]);
}
}
// Added my PlayerDetails.cs class also
public class PlayerDetails : INotifyPropertyChanged
{
[PrimaryKey, AutoIncrement]
public int id { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public byte[] PlayerImage { get; set; }
string fullname;
string mobile;
string soccerposition;
string email;
public PlayerDetails()
{
}
[Ignore]
public Image Image
{
get
{
var image = new Image();
image.Source = ImageSource.FromStream(() => new MemoryStream(PlayerImage));
return image;
}
set
{
//PlayerImage = Convert.ToByteArray(value.Source);
//Bitmap.FromStream(inStream);
}
}
public string FullName
{
set
{
if (fullname != value)
{
fullname = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("FullName"));
}
}
}
get
{
return fullname;
}
}
public string Mobile
{
set
{
if (mobile != value)
{
mobile = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Mobile"));
}
}
}
get
{
return mobile;
}
}
public string SoccerPosition
{
set
{
if (soccerposition != value)
{
soccerposition = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("SoccerPosition"));
}
}
}
get
{
return soccerposition;
}
}
public string Email
{
set
{
if (email != value)
{
email = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Email"));
}
}
}
get
{
return email;
}
}
//public ImageSource Source { get; internal set; }
public event PropertyChangedEventHandler PropertyChanged;
}
If you load an Image from a byte[] array in the Xamarin.Forms, you can try the following code:
c# code:
byte[] bitmapData = ...;
ImageSource imageSource= ImageSource.FromStream(() => new MemoryStream(bitmapData));
PlayerImage.Source = imageSource;//binding in code
The xaml code:
<Image x:Name="PlayerImage" WidthRequest="25" HeightRequest="25"/>
Or binding in xaml
<image Source="{Binding imageSource}"/>
Note:
I found the x:Name="{PlayerImage}" is not correct.
It's should be: x:Name="PlayerImage" not x:Name="{PlayerImage}"
you only need to use one way of the following binding methods:
PlayerImage.Source = imageSource;// in code
And
<Image x:Name="PlayerImage" Source="{Binding imageSource}" />
Update:
You can try to make use of a Converter derived from IValueConverter which could create the image back based on the byte array.
ByteArrayToImageSourceConverter.cs
public class ByteArrayToImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ImageSource retSource = null;
if (value != null)
{
byte[] imageAsBytes = (byte[])value;
var stream = new MemoryStream(imageAsBytes);
retSource = ImageSource.FromStream(() => stream);
}
return retSource;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
PlayerDetails.cs
public class PlayerDetails
{
// other fields
public byte[] PlayerImage { get; set; }
}
xaml(a usage example):
<ContentPage.Resources>
<ResourceDictionary>
<myformapp1:ByteArrayToImageSourceConverter x:Key="ByteArrayToImage"
/>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Margin="5">
<CollectionView x:Name="collectionView"
ItemsSource="{Binding YoudataList}"> <!--changd to your dataList-->
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
x:Name="PlayerPic"
Source="{Binding PlayerImage, Converter={StaticResource ByteArrayToImage}}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="test1"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="test2"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
It seems that I can't access it even if I put a name on it because it's inside a listview. If i wan row1 to not be visible on code behind how do i go around this?
I tried to a name for Label but I can't access it. or added I cant access on code behind.
<ListView x:Name="postListView" SeparatorVisibility="Default" HasUnevenRows="True" ItemsSource="{Binding Items}" SeparatorColor="White">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="Black" HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand" Padding="1,2,1,0">
<Grid HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand" ColumnSpacing="1" RowSpacing="1">
<Grid.RowDefinitions >
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" FontSize="Medium" Grid.Column="0" Text="right tst:" HorizontalTextAlignment="Start" BackgroundColor="cornflowerblue" />
<Label Grid.Column="1" Grid.Row="0" Text="{Binding drain1vol}" HorizontalTextAlignment="Center" BackgroundColor="cornflowerblue"/>
<Label Grid.Row="1" Grid.Column="0" Text="nothing" BackgroundColor="Yellow"/>
<Label Grid.Row="1" Grid.Column="1" Text="{Binding drain2vol}" HorizontalTextAlignment="Center" BackgroundColor="Yellow" />
</Grid>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
//Model and Source of data
using System;
using SQLite;
using Demo.Helpers;
namespace Demo.Model
{
//this is the source of Binding
public class Post
{
//ID primary key that we will autoincrement
//These are binding source for Historypage
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public bool showLabel { get; set; } //public class model
}
}
The source is the Post class.
Binding the label's IsVisible property to the property in your model to control the visiable ability of the label.
For example,
In xaml:
<Label Grid.Column="1" Grid.Row="0" IsVisible="{Binding showLabel}" Text="{Binding drain1vol}" HorizontalTextAlignment="Center" BackgroundColor="cornflowerblue"/>
And then in your model:
public class model
{
public string drain1vol { get; set; }
public bool showLabel { get; set; }
}
When you create the dataSource, you can set the label's isVisable:
Items.Add(new model { drain1vol = "Rob Finnerty" ,showLabel= false });
Items.Add(new model { drain1vol = "Bill Wrestler", showLabel = true });
Items.Add(new model { drain1vol = "Dr. Geri-Beth Hooper", showLabel = false });
Items.Add(new model { drain1vol = "Dr. Keith Joyce-Purdy", showLabel = true });
Items.Add(new model { drain1vol = "Sheri Spruce", showLabel = false });
postListView.ItemsSource = Items;
To change the visiable ability in code behind:
void test() {
//Get the model you want to change
model.showLabel = false / true;
}
Update:
Implement the INotifyPropertyChanged interface in your model:
class model : INotifyPropertyChanged
{
private bool showLabel { get; set; }
private string drain1vol { get; set; }
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
public bool ShowLabel
{
set
{
if (showLabel != value)
{
showLabel = value;
OnPropertyChanged("ShowLabel");
}
}
get
{
return showLabel;
}
}
public string Drain1vol
{
set
{
if (drain1vol != value)
{
drain1vol = value;
OnPropertyChanged("Drain1vol");
}
}
get
{
return drain1vol;
}
}
}
And in your xaml, binding to ShowLabel and Drain1vol(upper-case):
<Label Grid.Column="1" Grid.Row="0" IsVisible="{Binding ShowLabel}" Text="{Binding Drain1vol}" HorizontalTextAlignment="Center" BackgroundColor="cornflowerblue"/>
I have listbox which contains buttons listed vertically with related datas as given below;
<ListBox Name="CTransactionList" Margin="0,0,0,0" >
<ListBox.ItemTemplate >
<DataTemplate>
<Button Width="400" Height="200" Background="#6A040B2E" Click="completetransact">
<Button.Content >
<StackPanel Orientation="Horizontal" Height="200" Width="400">
<Image Source="{Binding Type1}" Width="80" Height="80" VerticalAlignment="Top" Margin="0,40,0,0"/>
<StackPanel Orientation="Vertical" Height="200">
<StackPanel Orientation="Horizontal" Height="30">
<TextBlock Width="100" FontSize="22" Text="Name:" Height="30"/>
<TextBlock Width="200" FontSize="22" Text="{Binding Date1}" Height="30"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="30">
<TextBlock Width="100" FontSize="22" Text="Difficulty:" Height="30"/>
<TextBlock Width="200" FontSize="22" Text="{Binding Amount1}" Height="30"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="30">
<TextBlock Width="110" FontSize="22" Text="TotalTime:" Height="30"/>
<TextBlock Width="200" FontSize="22" Text="{Binding Time1}" Height="30"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="30">
<TextBlock Width="100" FontSize="22" Text="Distance:" Height="30"/>
<TextBlock Width="200" FontSize="22" Text="{Binding Dis1}" Height="30"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="65">
<TextBlock Width="290" FontSize="14" Text="{Binding Def1}" Height="65" TextWrapping="Wrap" FontStyle="Italic"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Button.Content>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And I'm binding the data with such classes;
[DataContract]
public class CTransaction
{
[DataMember]
public String Date1 { get; set; }
[DataMember]
public String Amount1 { get; set; }
[DataMember]
public String Type1 { get; set; }
[DataMember]
public String Time1 { get; set; }
[DataMember]
public String Dis1 { get; set; }
[DataMember]
public String Def1 { get; set; }
[DataMember]
public String Cdate1 { get; set; }
[DataMember]
public String Strpt1 { get; set; }
[DataMember]
public String Endpt1 { get; set; }
[DataMember]
public int Index1 { get; set; }
public CTransaction(String date1, String amount1, String type1, String time1, String dis1, String def1, String cdate1, String strpt1, String endpt1,int index1)
{
this.Date1 = date1;
this.Amount1 = amount1;
this.Time1 = time1;
this.Dis1 = dis1;
this.Def1 = def1;
this.Cdate1 = cdate1;
this.Strpt1 = strpt1;
this.Endpt1 = endpt1;
this.Index1 = index1;
switch (type1)
{
case "FR":
this.Type1 = "Images/a.png";
break;
case "TA":
this.Type1 = "Images/b.png";
break;
case "DA":
this.Type1 = "Images/c.png";
break;
case "CC":
this.Type1 = "Images/mount.png";
break;
}
}
}
As shown above, I have a data binding named Index1 which indexes the button with an arbitrary integer. I want to remove a specified indexed button by user with this code;
ctransactionList.RemoveAt("index comes here");
My exact desire is to remove the clicked button,(i.e. if the second button clicked, then remove the second one). And I tried to embed some indexes(i.e. Index1) in it to remove it, I couldn't find any possible way; I also failed again.
This is the way I tried;
The removal code given above only removes the indexed item based on the whole list item count. I mean, for example, the first element always has the '0' index. It does not care my Index1 data.(I can retrieve the Index1 data with selectedButton as sender method) I wish I could have removed the button which includes the user-specified Index1 data.
How can I do this?
Thanks in advance.
(Windows Phone 7)
You can do this by adding click event handler for button:
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
var item = button.DataContext as CTransaction;
if (item != null)
{
ctransactionList.Remove(item);
}
}
ctransactionList should be an ObservableCollection.
I'm trying to have a TextBox's content be validated using IDataErrorInfo. The source of the list below is a List and each item is display. When i put ValidatesOnDataErrors=True in the Binding for the Text on the TextBox, it's not working as expected. How do I do this?
<ItemsControl ItemsSource="{Binding Trainings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel>
<TextBlock Text="{Binding MobileOperator}" />
<TextBlock Text="{Binding LastUpdate}"/>
</StackPanel>
<StackPanel>
<TextBlock Text="Number trained*" />
<!-- ValidatesOnDataErrors doesn't work here-->
<TextBox
Text="{Binding NumberTrained,
ValidatesOnDataErrors=True}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Update: Posting a stripped down version of Model, ViewModel, View and CodeBehind
ViewModel and Model
public class MyViewModel : IDataErrorInfo, INotifyPropertyChanged
{
public MyViewModel()
{
Trainings = new List<MyModel>
{
new MyModel { NumberTrained = 5, MobileOperator = "MO 1", LastUpdate = DateTime.Now },
new MyModel { NumberTrained = 1, MobileOperator = "MO 2", LastUpdate = DateTime.Now },
};
OkButtonCommand = new ButtonCommand(OnClick);
}
private void OnClick()
{
PropertyChanged(this, new PropertyChangedEventArgs(""));
}
public event PropertyChangedEventHandler PropertyChanged;
public ICommand OkButtonCommand { get; private set; }
public List<MyModel> Trainings { get; private set; }
public string Error { get { return null; } }
public string this[string columnName]
{
get
{
string error = null;
switch (columnName)
{
case "NumberTrained":
error = "error from IDataErrorInfo";
break;
}
return error;
}
}
}
public class MyModel
{
public string MobileOperator { get; set; }
public DateTime LastUpdate { get; set; }
public int NumberTrained { get; set; }
}
public class ButtonCommand : ICommand
{
private Action _handler;
public event EventHandler CanExecuteChanged;
public ButtonCommand(Action handler) { _handler = handler; }
public bool CanExecute(object parameter) { return true; }
public void Execute(object parameter) { _handler(); }
}
Code Behind
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
View
<Canvas x:Name="LayoutRoot" Background="White">
<ItemsControl ItemsSource="{Binding Trainings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="{Binding MobileOperator}" Margin="15,15,0,0" FontWeight="Bold"/>
<TextBlock Text="{Binding LastUpdate, StringFormat=' - Last Updated: \{0:M/d/yy\}'}"
Margin="5,15,15,0" Foreground="Gray"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="Number trained*" />
<TextBox Width="50" Height="20"
Text="{Binding NumberTrained, Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="ok" Width="100" Height="20" Canvas.Left="248" Canvas.Top="207" Command="{Binding OkButtonCommand}"/>
</Canvas>
I feel implementing IDataErrorInfo on ViewModel is more appropriate rather than on Model.
So in your case, you could have created an additional ViewModel (ex: MyModelViewModel) and include it as a List<MyModelViewModel> inside MyViewModel to be used as the ItemsSource.
Going by MVVM, if you feel you should have a corresponding View for it, you can extract out the DataTemplate of the ItemsControl to a new XMAL.
You need to implement IDataErrorInfo on your Model, not your ViewModel.
As it is right now, your a validation check is throwing an error when you try and validate the property MyViewModel.NumberTrained, which doesn't exist, so the validation error never gets called.