How to notify XAML properties when list data of binding changed? - c#

I'm using the following code for binding
XAML
<StackPanel x:Name="channelsRecordTimeData" Orientation="Vertical">
<ItemsControl x:Name="channelRecordTimeItems" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="gridChannelRecordTimeItem" Width="{Binding Path=ChannelRecordTimeItemWidth}"
Height="{Binding Path=ChannelRecordTimeItemHeight}" Margin="{Binding Path=ChannelRecordTimeItemsMargin}"
HorizontalAlignment="Left" DataContext="{Binding Path=ListRecordTime}">
<Grid.Background>
<ImageBrush x:Name="gridChannelRecordTimeItemBgr" ImageSource="..\Resources\playback_grid_channel_record_time_item_bgr_normal.png"/>
</Grid.Background>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
C#
public class DATA
{
public double ChannelRecordTimeItemWidth { set; get; }
public double ChannelRecordTimeItemHeight { set; get; }
public Thickness ChannelRecordTimeItemsMargin { set; get; }
public List<RecordTime> ListRecordTime { set; get; }
public DATA()
{
ChannelRecordTimeItemWidth = 1000;
ChannelRecordTimeItemHeight = 20;
ChannelRecordTimeItemsMargin = new System.Windows.Thickness(0, 0, 0, 0);
ListRecordTime = null;
}
}
public static List<DATA> listDATA = new List<DATA>();
for(int i = 0 ; i < 10 ; i++)
{
DATA data = new DATA();
listDATA.Add(data);
}
channelRecordTimeItems.ItemsSource = listDATA;
channelRecordTimeItems.Items.Refresh();
This code will notify to the XAML update when I use the line of code as
listDATA[0].ChannelRecordTimeItemWidth -= 15;
There is any way to XAML update properties automatically, when we manipulate on the listDATA as
listDATA.RemoveAt();
listDATA.Add();
listDATA.Clear();
Without calling the two following lines code
channelRecordTimeItems.ItemsSource = listDATA;
channelRecordTimeItems.Items.Refresh();

GUI will be updated only in case underlying source collection is implementing INotifyCollectionChanged which raise CollectionChanged events to refresh GUI components.
You can use ObservableCollection which internally provides you this feature.
Replace
public static List<DATA> listDATA = new List<DATA>();
with
public static ObservableCollection<DATA> listDATA = new ObservableCollection<DATA>();

Related

WPF Image display not updated after source is changed

In my MainView there is a ContentControl which is bound to a CurrentView object. The CurrentView is changed via buttons on the MainView bound to commands.
MainView
<Window>(...)
<RadioButton Content="View1"
Command="{Binding View1Command}"/>
<RadioButton Content="View2"
Command="{Binding View2Command}"/>
<ContentControl Content="{Binding CurrentView}"/>
</Window>
MainVM
(The ObservableObject class implements INotifyPropertyChanged and the RelayCommand class ICommand.)
class MainViewModel : ObservableObject
{
public RelayCommand ViewCommand1 { get; set; }
public RelayCommand ViewCommand2 { get; set; }
public ViewModel2 VM1 { get; set; }
public ViewModel2 VM2 { get; set; }
object _currentView;
public object CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
VM1 = new ViewModel1();
VM1.ContentChanged += (s, e) => OnPropertyChanged();
ViewCommand1 = new RelayCommand(o =>
{
CurrentView = VM1;
});
VM2 = new ViewModel2();
ViewCommand2 = new RelayCommand(o =>
{
CurrentView = VM2;
});
}
}
Those (sub) VM are bound to UserControls which contain image controls and a button to load the image sources from files.
View1
<UserControl x:Class="Project.Views.View1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:viewModels="clr-namespace:Project.ViewModels"
d:DataContext="{d:DesignInstance Type=viewModels:ViewModel1}"
mc:Ignorable="d" >
[...]
<Button Command="{Binding LoadImagesCommand}"/>
[...]
<Image Source="{Binding Images[0]}" "/>
<Image Source="{Binding Images[1]}" "/>
[...]
</UserControl>
VM1
class RiJustageViewModel: ObservableObject
{
public event EventHandler ContentChanged;
void OnContentChanged()
{
ContentChanged?.Invoke(this, new EventArgs());
}
public RelayCommand LoadImagesCommand { get; set; }
public ViewModel1()
{
Images = new BitmapImage[9];
LoadImagesCommand = new RelayCommand(o => LoadImages());
}
BitmapImage[] _images;
public BitmapImage[] Images
{
get { return _images; }
set
{
_images = value;
OnContentChanged();
}
}
public void LoadImages()
{
[...]
for (int i = 0; i < files.Length; i++)
{
Images[i] = Utility.BmImageFromFile(files[i]);
}
[...]
}
}
The issue now is that the images are not shown right away after they are loaded. Only after I change the content of the ContentControl to another view and then back to View1 the images are shown.
Is there a way to trigger that display right after the loading is complete without changing the content of the ContentControl?
EDIT:This should be done everytime the user wants to load new images via the button, not only during initialization.
EDIT:
With lidqy's and EldHasp's comments I was able to clean up the VM and the View using ObservableCollection and ItemsControl.
VM
public class ImageItem
{
public string FileName{ get; set; }
public ImageSource Image { get; set; }
public ImageItem(string f, ImageSource im)
{
FileName = f;
Image = im;
}
}
public ObservableCollection<ImageItem> ImageItems { get; set; }
[...]
public void LoadImages()
{
[...]
ImageItems.Clear();
foreach (var file in files)
{
var im = Utility.BmImageFromFile(file);
var f = Path.GetFileName(file);
ImageItems.Add(new ImageItem(f, im));
}
}
View
<ItemsControl ItemsSource="{Binding ImageItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3" Rows="3"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="400"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="18" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding FileName}" Style="{StaticResource ImageDescr}" />
<Image Grid.Row="1" Source="{Binding Image}" Style="{StaticResource ImageTheme}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Very neat.
The ContentChanged event is useless.
Declare the Images property like this:
private ImageSource[] images;
public ImageSource[] Images
{
get { return images; }
set
{
images = value;
OnPropertyChanged();
}
}
In LoadImages(), just assign a new array:
public void LoadImages()
{
...
Images = files
.Select(f => Utility.BmImageFromFile(f))
.ToArray();
}
class RiJustageViewModel: ObservableObject
{
public event EventHandler ContentChanged;
void OnContentChanged()
{
ContentChanged?.Invoke(this, new EventArgs());
}
public RelayCommand LoadImagesCommand { get; set; }
public ViewModel1()
{
// If this is not an observable collection,
// then it makes no sense to create it in advance.
// Images = new BitmapImage[9];
LoadImagesCommand = new RelayCommand(o => LoadImages());
}
// Since it is not an observable collection,
// the more general interface can be used: IEnumerable or IEnumerable <T>.
IEnumerable<BitmapImage> _images;
public IEnumerable<BitmapImage> Images
{
get { return _images; }
set
{
_images = value;
OnContentChanged();
}
}
public void LoadImages()
{
[...]
// For an unobservable collection,
// changing elements does not automatically change their presentation.
// We need to create a NEW collection with
// new elements and assign it to the property.
BitmapImage[] localImages = new BitmapImage[files.Length];
for (int i = 0; i < files.Length; i++)
{
localImages[i] = Utility.BmImageFromFile(files[i]);
}
Images = localImages;
[...]
}
}
This implementation has a drawback - it creates a new collection of images each time.
From memory, it doesn't matter (compared to other WPF costs).
But replacing a collection results in a re-creation of the UI elements that represent it.
And this is already significantly longer delays.
For your task, this is also not important, since this happens very rarely.
But for more loaded scenarios, it is better to use an observable collection (INotifyCollectionChanged) or a bindable list (IBindingList).
It is typical for WPF to use ObservableCollection<T>.
But in the case of asynchronous work with them, you need to take measures to work with it was thread-safe.
For the implementation I have shown, thread safety is not needed.
This is already implemented in the Binding mechanism itself to work with the INotifyPropertyChanged interface.
If you want to display all the images of the _images collection of the current view model (which is the "current view") I would display them in a ListBox and put the image tag and the binding into the ListBox's ItemTemplate.
Also as previously mentioned by others, using an ObservableCollecztion<ImageSource> is strongly recommended since your collection data changes and you want your UI to notice it.
If you don't use an ObservableCollection, the view and images get only updated if the view model as a whole changes.

Populating a ComboBox with a Array in C#

My Array is a list of Pokemon Names read from a text file and then stored into an Array in the PokemonData class seen below
private string[] pokemonNames;
private StreamReader readNames;
public PokemonData()
{
readNames = new StreamReader(setDirectory() + #".\PokemonNames.txt");
pokemonNames = new string[256];
populateArray(pokemonNames, readNames);
}
public string[] populateArray(string[] pokemonNames, StreamReader readNames)
{
string pokemonName = readNames.ReadLine();
int i = 0;
while (pokemonName != null)
{
pokemonNames[i] = pokemonName.Trim();
pokemonName = readNames.ReadLine();
i++;
}
readNames.Close();
return pokemonNames;
}
public string[] getPokemonNames()
{
return pokemonNames;
}
What I want to do is now populate an Combobox using WPF with all the names inside the array. I have tried googling this and frequently alot of the answers have classes setup much like this:
Class ExampleClass {
Public ExampleClass() {
string PokemonName; {get; set;}
}
}
I believe there is an assignment going on here, but I am unsure. C# isn't my usual language and this is my first time creating a gui. Could someone please guide me through so I could finish this.
I have tried doing a handful of things such as the code below and Databinding. At this point I believe I am missing something.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StarterEdit"
xmlns:Collections="clr-namespace:System.Collections;assembly=System.Runtime.Extensions" x:Class="StarterEdit.MainWindow"
mc:Ignorable="d"
Title="Starter Edit" Height="420" Width="550">
<Grid Margin="0,0,0,11" HorizontalAlignment="Center" Width="530">
<Label Content="Squirtle" HorizontalAlignment="Left" Margin="45,50,0,0" VerticalAlignment="Top" ToolTip="Starter One"/>
<Label Content="Bulbasaur" HorizontalAlignment="Left" Margin="245,50,0,0" VerticalAlignment="Top" ToolTip="Starter Two"/>
<Label Content="Charmander" HorizontalAlignment="Left" Margin="445,50,0,0" VerticalAlignment="Top" ToolTip="Starter Three"/>
<ComboBox x:Name="NameList" HorizontalAlignment="Left" Margin="10,81,0,0" VerticalAlignment="Top" Width="120" IsReadOnly="True" SelectedIndex="0" Cursor="Arrow" IsTextSearchEnabled="True" ToolTip="List of Pokemon names">
</ComboBox>
</Window>
Here is my MainWindow class
public partial class MainWindow : Window
{
Dictionary<int, string> pokemonNames = new Dictionary<int, string>();
PokemonData pokemonData = new PokemonData();
public MainWindow()
{
InitializeComponent();
NameList.ItemsSource = pokemonData.getPokemonNames(); //method that returns string array
NameList.ItemsSource = pokemonNames; //this is a dictionary
}
}
What I'm trying to do is using WPF I want to populate my comboBox with the data from the PokemonData Class, specifically the array containing all the names. The problem is whenever I bind the data or set the data it never displays on the gui or in the comboBox.
If shortly, the next code must work correctly, just do this initialization after loading data from the file.
NameList.ItemsSource = pokemonData.getPokemonNames();
If you want a better solution, you can find it below (when Pokemons collection have changed UI would be updated automatically):
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new PokemonData(setDirectory() + #".\PokemonNames.txt");
}
}
public class Pokemon
{
public int ID { get; set; }
public string Name { get; set; }
}
public class PokemonData
{
public ObservableCollection<Pokemon> Pokemons { get; set; } = new ObservableCollection<Pokemon>();
public PokemonData(string path)
{
LoadData(path);
}
private void LoadData(string path)
{
Pokemons.Clear();
using (StreamReader stream = new StreamReader(path))
{
int i = 1;
while (true)
{
string pokemonName = stream.ReadLine();
if (pokemonName != null)
Pokemons.Add(new Pokemon { ID = i, Name = pokemonName.Trim() });
else break;
i++;
}
}
}
}
And XAML code:
<ComboBox ItemsSource="{Binding Pokemons}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Two different DataTemplate

I have two ListBoxs defined in my XAML and one Class MyListItem.
Now one ListBox should display the name as button and the second ListBox should display the name as a TextBlock.
Here a little example, both ListBoxs behave the same.
MyListItem
public class MyListItem
{
private string _name;
public string Name
{
get{return _name;}
set{_name = value;}
}
}
XAML
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataTemplate.Views.MainWindow"
xmlns:viewsmodels="clr-namespace:DataTemplate.ViewModels;assembly=DataTemplate"
xmlns:dt="clr-namespace:DataTemplate;assembly=DataTemplate"
Title="DataTemplate" Width="700">
<Window.DataContext>
<viewsmodels:MainWindowViewModel />
</Window.DataContext>
<Grid ColumnDefinitions="250,250,250">
<ItemsControl Grid.Column="1" Items="{Binding List2}">
<ItemsControl.DataTemplates>
<DataTemplate DataType="{x:Type dt:MyListItem}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.DataTemplates>
</ItemsControl>
<ItemsControl Grid.Column="2" Items="{Binding List3}">
<ItemsControl.DataTemplates>
<DataTemplate DataType="{x:Type dt:MyListItem}">
<Button Content="{Binding Name}"/>
</DataTemplate>
</ItemsControl.DataTemplates>
</ItemsControl>
</Grid>
</Window>
ViewMode
public class MainWindowViewModel
{
public ObservableCollection<MyListItem> List1 { get; set; }
public ObservableCollection<MyListItem> List2 { get; set; }
public ObservableCollection<MyListItem> List3 { get; set; }
public MainWindowViewModel()
{
List1 = new ObservableCollection<MyListItem>();
List2 = new ObservableCollection<MyListItem>();
List3 = new ObservableCollection<MyListItem>();
Random rand = new Random();
for (int i = 0; i < rand.Next(1, 20); i++)
{
MyListItem mli = new MyListItem();
mli.Name = "ListItem" + i;
List1.Add(mli);
}
for (int i = 0; i < rand.Next(1, 20); i++)
{
MyListItem mli = new MyListItem();
mli.Name = "ListItem" + i;
List2.Add(mli);
}
for (int i = 0; i < rand.Next(1, 20); i++)
{
MyListItem mli = new MyListItem();
mli.Name = "ListItem" + i;
List3.Add(mli);
}
}
}
Unfortunately there's currently no good way to do this in Avalonia that I can think of. The most obvious way would be to add the data templates to a <Style.Resources> collection and use {StyleResource} to reference them, but this doesn't work currently.
I think you have two alternatives here for the moment:
Just copy and paste the data templates into the ItemsControl.ItemTemplate
Define the data templates in code and reference them using {Static}. For this you can use FuncDataTemplate<>
I've added an issue to track this problem here: https://github.com/AvaloniaUI/Avalonia/issues/1020
You need to use ItemsControl instead of ListBox and have ItemTemplate set differently for each of them.
One will point to DataTemplate(using x:Key, not DataType) with TextBlock, and the other to DataTemplate with Button.

Data Binding a DataGrid to an Object with Nested Classes

So I have an api call that runs a query and returns a JSON response. Because of the structure of the JSON response I have created a class that I can use Json.Net to Deserialize the return straight into. Here is the example class:
public class QuerySet
{
public List<Column> Columns { get; set; }
public class Column
{
public List<string> Name { get; set; }
}
public List<RowSet> Rows { get; set; }
public class RowSet
{
public List<DataSet> Row { get; set; }
public class DataSet
{
public List<string> Data { get; set; }
}
}
}
Now, a single API call can contain several query sets, so for each return, I generate a list of query sets, that I then want to data bind a DataGrid to each set. Here is an example of what I have so far in the code behind my window:
public List<DataGrid> QueryResults;
public QueryResultsWindow(string _name, JObject _returns)
{
InitializeComponent();
QueryNameText.Text = _name;
QueryResults = new List<DataGrid>();
JArray sets = (JArray)_returns.SelectToken("$..Set");
foreach(JObject set in sets)
{
DataGrid dg = new DataGrid();
QuerySet s = new QuerySet();
s = JsonConvert.DeserializeObject<QuerySet>(set.ToString());
dg.ItemsSource = s.Rows;
QueryResults.Add(dg);
}
ResultsListBox.ItemsSource = QueryResults;
}
The issue here as you might see is that for each particular DataGrid, I want the Column Headers bound to the Name property, and the data populated from the Data properties.
Here is how I currently have the XAML setup in the window:
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" VerticalAlignment="Top">
<TextBlock x:Name="QueryNameText" Margin="5"></TextBlock>
<Button Content="Export Results" Click="Button_Click" Margin="5"></Button>
</StackPanel>
<ListBox DockPanel.Dock="Top" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="3" Name="ResultsListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<DataGrid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding UpdateSourceTrigger=PropertyChanged}" CanUserAddRows="False" IsReadOnly="True" SelectionUnit="Cell">
<DataGrid.Columns>
<DataGridTextColumn Header="{Binding Name}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
I know that if I wanted to create a custom class for each possible return type, this would be much easier. However, given the hundreds of potential return types, this does not seem very feasible. I've tried using DataTables, I've tried setting the DataGrid in the ListBox in XAML, but I may not have implemented this correctly, and finally came to the resolution of trying to create a list of DataGrids and then binding to those.
I could use some help.
Thanks!
SO after some messing around with this. Here is the answer I came up with.
I took the query set class above and added a method to build a DataTable inside the QuerySet Class:
public class QuerySet
{
public DataTable BindableTable { get; private set; }
public static List<string> ColumnName { get; private set; }
public static List<RowSet.DataSet> RowsSet { get; private set; }
public List<Column> Columns { get; set; }
public class Column
{
private List<string> _name;
public List<string> Name
{
get { return _name; }
set { _name = value; ColumnName = _name; }
}
}
public List<RowSet> Rows { get; set; }
public class RowSet
{
private List<DataSet> _row;
public List<DataSet> Row
{
get { return _row; }
set { _row = value; RowsSet = _row; }
}
public class DataSet
{
public List<string> Data { get; set; }
}
}
public void GetDataGridTable()
{
DataTable table = new DataTable();
foreach(string name in ColumnName)
{
table.Columns.Add(name);
}
foreach(RowSet.DataSet set in RowsSet)
{
DataRow row = table.NewRow();
int counter = 0;
foreach(string item in set.Data)
{
row[counter] = item;
counter++;
}
table.Rows.Add(row);
}
BindableTable = table;
}
}
I added a couple of accessors to make getting to the nested bits easier, and built a DataTable from there. In my code behind my popup window, I created an Observable Collection of DataGrids, and set the DataContext of each Grid to a DataView based on the QuerySet:
public ObservableCollection<DataGrid> QueryResults;
public event PropertyChangedEventHandler PropertyChanged;
public QueryResultsWindow(string _name, JObject _returns)
{
InitializeComponent();
QueryNameText.Text = _name;
QueryResults = new ObservableCollection<DataGrid>();
JArray sets = (JArray)_returns.SelectToken("$..Set");
foreach(JObject set in sets)
{
DataGrid dg = new DataGrid();
QuerySet s = new QuerySet();
s = JsonConvert.DeserializeObject<QuerySet>(set.ToString());
s.GetDataGridTable();
DataView newView = new DataView(s.BindableTable);
dg.ItemsSource = newView;
dg.CanUserAddRows = false;
dg.CanUserDeleteRows = false;
QueryResults.Add(dg);
}
ResultsListBox.ItemsSource = QueryResults;
}
Then the XAML inside my popup window was pretty straight forward:
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" VerticalAlignment="Top">
<TextBlock x:Name="QueryNameText" Margin="5"></TextBlock>
<Button Content="Export Results" Click="Button_Click" Margin="5"></Button>
</StackPanel>
<ListBox DockPanel.Dock="Top" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="3" Name="ResultsListBox" ItemsSource="{Binding QueryResults}">
</ListBox>
</DockPanel>
Obviously this is not the most elegant solution. Even just looking at it here I could easily create the DataView in the QuerySet class rather than doing that conversion in the code behind. So, while the answer isn't perfect, it's working for now.

Design Time Data in Universal App

While I can created some Design Time Sample Data in both WP8 Silverlight and Runtime App (Windows 8.1), I can't set them in my new Universal App (windows 10).
As what this man showed here , Sample data'll simply show up both in design time and run time.
But when I try, It only shows the name of properties in design view.
Here is my code:
public class SampleModel
{
public string Name { get; set; }
public Uri Image { get ;set; }
}
public class DesignTimeSampleModel
{
public ObservableCollection<SampleModel> SampleList { get; set; }
public DesignTimeSampleModel()
{
SampleList = new ObservableCollection<SampleModel>;
for (int i = 0; i < 10; i++)
{
SampleList.Add(new SampleModel() {
Name = "Design Data",
Image = new Uri("ms-appx:///Assets/StoreLogo.png", UriKind.Absolute);
});
}
}
}
Finally in my MainPage
<Page
xmlns:vm="using:UWP_Test_Binding.ViewModels"
.......
>
<d:Page.DataContext>
<vm:DesignTimeSampleModel/>
</d:Page.DataContext>
<Grid>
<ListView ItemsSource="{Binding SampleList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" Style="{StaticResource NameTextBlock}"/>
<Image Source="{Binding Image}" MaxHeight="50"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Even when I changed the datacontext in XAML like
<Page.DataContext>
<vm:DesignTimeSampleModel/>
</Page.DataContext>
or what i've done in WP8 silverlight
d:DataContext="{Binding Source={d:DesignInstance Type=vm:DesignTimeSampleModel, IsDesignTimeCreatable=True}}"
or set context in code-behind
public MainPage()
{
this.InitializeComponent();
this.DataContext = new ViewModels.DesignTimeSampleModel();
}
My sample data doesn't show in XAML view
I tried to copy your code and create a new project to test it. There is an error in your view model:
In this line:
SampleList = new ObservableCollection<SampleModel>;
Try this DesignTimeSampleModel:
public class DesignTimeSampleModel
{
public ObservableCollection<SampleModel> SampleList { get; set; }
public DesignTimeSampleModel()
{
SampleList = new ObservableCollection<SampleModel>();
for (int i = 0; i < 10; i++)
{
SampleList.Add(new SampleModel()
{
Name = "Design Data",
Image = new Uri("ms-appx:///Assets/StoreLogo.png", UriKind.Absolute)
});
}
}
}

Categories