I'm using Flipview and a DataTemplateSelector to determine at runtime which DataTemplate to apply to show items in my control.
I have two DataTemplate's, one is static and the second can be used by a undetermined number of items.
Currently
My first view displays:
- "This is a test - Content"
Followed by 18 other views that look like this:
- "http://www.google.com/ 0"
- "http://www.google.com/ 1"
- "http://www.google.com/ 2"
- and so on until 17
I want
The items "http://www.google.com/ " to be grouped as 3 on a view.
For example the second view will display:
"http://www.google.com/ 0, http://www.google.com/ 1, http://www.google.com/ 2"
The third view will display:
"http://www.google.com/ 3, http://www.google.com/ 4, http://www.google.com/ 5"
And so on..
Bellow is my code:
FlipViewDemo.xaml
<Page.Resources>
<DataTemplate x:Key="FirstDataTemplate">
<Grid>
<TextBlock Text="{Binding Content}" Margin="10,0,18,18"></TextBlock>
</Grid>
</DataTemplate>
<DataTemplate x:Key="SecondDataTemplate">
<TextBox Text="{Binding Url}"></TextBox>
</DataTemplate>
<local:MyDataTemplateSelector x:Key="MyDataTemplateSelector"
FirstTextTemplate="{StaticResource FirstDataTemplate}"
SecondTextTemplate="{StaticResource SecondDataTemplate}">
</local:MyDataTemplateSelector>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<FlipView x:Name="itemGridView" ItemTemplateSelector="{StaticResource MyDataTemplateSelector}"
Margin="265,220,284,162">
</FlipView>
</Grid>
FlipViewDemo.xaml.cs
public sealed partial class FlipViewDemo : Page
{
public FlipViewDemo()
{
this.InitializeComponent();
var items = new List<BaseClass>();
items.Add(new FirstItem
{
Content="This is a test - Content"
});
for (int i = 0; i < 18; i++)
{
items.Add(new SecondItem
{
Url = "http://www.google.com/ " + i.ToString()
});
}
itemGridView.ItemsSource = items;
}
}
public class BaseClass
{
}
public class FirstItem : BaseClass
{
public string Content { get; set; }
}
public class SecondItem : BaseClass
{
public string Url { get; set; }
}
public class MyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate FirstTextTemplate { get; set; }
public DataTemplate SecondTextTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item,
DependencyObject container)
{
if (item is FirstItem)
return FirstTextTemplate;
if (item is SecondItem)
return SecondTextTemplate;
return base.SelectTemplateCore(item, container);
}
}
I'm thinking that maybe this can be achieved with groups and list view. But I'm not sure how this can be done.
Probably it is a stupid question but, using Google, I can't find an answer. Also english is not my native language; please excuse typing errors.
I think the way to achieve what you are looking for is to expose the data in a way that better represents what you want to display. Then, you can use nested controls to display it. I just threw this together (using my own test data). It is probably not exactly what you want, but it should help you figure things out.
ViewModel
Here I made a helper method to build the collection with sub-collections that each have 3 items.
class FlipViewDemo
{
private List<object> mData;
public IEnumerable<object> Data
{
get { return mData; }
}
public FlipViewDemo()
{
mData = new List<object>();
mData.Add("Test String");
for (int i = 0; i < 18; ++i)
{
AddData("Test Data " + i.ToString());
}
}
private void AddData(object data)
{
List<object> current = mData.LastOrDefault() as List<object>;
if (current == null || current.Count == 3)
{
current = new List<object>();
mData.Add(current);
}
current.Add(data);
}
}
class TemplateSelector : DataTemplateSelector
{
public DataTemplate ListTemplate { get; set; }
public DataTemplate ObjectTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is List<object>) return ListTemplate;
return ObjectTemplate;
}
}
Xaml
Here I use an ItemsControl to vertically stack the items in the data. Each item is either a list of three objects or a single object. I use a FlipView for each of the lists of three objects and a simple ContentPresenter for the single objects.
<Page.Resources>
<DataTemplate x:Key="ListTemplate">
<FlipView
ItemsSource="{Binding}">
<FlipView.ItemTemplate>
<DataTemplate>
<ContentPresenter
Margin="0 0 10 0"
Content="{Binding}" />
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</DataTemplate>
<DataTemplate x:Key="ObjectTemplate">
<ContentPresenter
Margin="0 0 10 0"
Content="{Binding}" />
</DataTemplate>
<local:TemplateSelector
x:Key="TemplateSelector"
ListTemplate="{StaticResource ListTemplate}"
ObjectTemplate="{StaticResource ObjectTemplate}" />
</Page.Resources>
<ItemsControl
ItemsSource="{Binding Data}"
ItemTemplateSelector="{StaticResource TemplateSelector}" />
Note: You usually would not need a template selector for something like this, but since you need to select between a List<T> and an Object, there is no way I know of to recognize the difference using only the DataTemplate.TargetType property from Xaml due to List<t> being a generic type. (I tried {x:Type collections:List`1} and it did not work.)
You need to group items in viewmodel, and databind ItemsSource to the groups. In flipview's itemtemplate you display items in group.
public class PageGroup : PageBase {
public ObservableColection<BaseClass> Items { get; set; }
}
public ObservableCollection<PageBase> Pages { get; set; }
<FlipView ItemsSource="{Binding Pages}">
<FlipView.ItemTemplate>
<DataTemplate DataType="local:PageGroup">
<ItemsControl ItemsSource="{Binding Items}"
ItemTemplateSelector="{StaticResource MyDataTemplateSelector}" />
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
In order to display first page differently from others:
public class FirstPage : PageBase {
public string Title { get; }
}
Pages.Insert(0, new FirstPage());
and you need to use another datatemplaeselector or impicit datatemplates in FlipView to differentiate between FirstPage and PageGroup
<FlipView ItemsSource="{Binding Pages}"
ItemTemplateSelector="{StaticResource PageTemplateSelector}" />
You don't need to worry about selecting the appropriate template based on the class type, you can simply define the class in the DataTemplate itself.
<DataTemplate TargetType="{x:Type myNamespace:FirstItem}">
...
</DataTemplate>
You'll need to specify where the class is by adding the namespace at the top of your page:
xmlns:myNamespace="clr-namespace:MyApp.MyNamespace"
Related
So I'm creating "cards" to visually represent a collection of objects within a StackPanel (which I'm using a list to hold these objects):
MainWindow XAML:
<Window /* ... */>
<StackPanel x:Name="Deck" Orientation="Horizontal" />
</Window>
MainWindow C#:
public partial class MainWindow : Window
{
/* ... */
private void OnDataReceived(List<Reading> readings)
{
foreach(Reading r in readings)
{
Deck.Children.Add(new Card
{
Id = r.Id,
Value = r.Value
});
}
}
}
UserControl XAML:
<UserControl /* ... */ x:Name="crd">
<Label Content="{Binding Path=Id, ElementName=crd}" />
<Label Content="{Binding Path=Value, ElementName=crd} />
</UserControl>
UserControl C#:
public partial class LoggerRepresentation : UserControl
{
public string Id { get; set; }
public int Value { get; set; }
/* ... */
}
Upon adding one element to Deck.Children, its' visual representation does appear in the StackPanel as expected. However, DP seems to lack something as the Labels binding Id and Value remain empty.
(The idea to give x:Name="crd" to my UserControl and then use it within the Binding as ElementName has been plugged from the answer to a seemingly related question, but may be misleading in this case.)
You should use an ItemsControl whenever you want to display a dynamic collection of items.
Replace the StackPanel in your XAML markup with an ItemsControl:
<ItemsControl ItemsSource="{Binding Cards}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:LoggerRepresentation />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Bind directly to the source properties of the corresponding Card object in the UserControl (and replace the Label elements with TextBlocks):
<TextBlock Text="{Binding Path=Id}" />
<TextBlock Text="{Binding Path=Value} />
Create a view model class that exposes a collection of Card objects through a public property and move your application logic over to this one:
public class ViewModel
{
public ObservableCollection<Card> Cards { get; } = new ObservableCollection<Card>();
//...
private void OnDataReceived(List<Reading> readings)
{
foreach (Reading r in readings)
{
Cards.Add(new Card
{
Id = r.Id,
Value = r.Value
});
}
}
}
Set the DataContext of the view where the ItemsControl is defined to an instance of the view model class:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
This design pattern is known as Model-View-ViewModel (MVVM) and it's the recommended pattern to use when developing XAML based UI applications. You will find a lot more to read and learn about it if your Google.
I am working with visual studio 2017. And I wand to display two type of list view items in a list view. That means two different custom data templates.
And This is my xaml page
<Page
x:Class="InboxModule.ChatMessages"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:InboxModule"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="leftTemplate">
<StackPanel Background="Aqua" Orientation="Horizontal">
<TextBlock Text="left"/>
<TextBlock Text="{Binding LastMessage}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="rightTemplate">
<Grid Background="White">
<TextBlock Text="right"/>
</Grid>
</DataTemplate>
<local:MyDataTemplateSelector x:Key="myPremiumUserDataTemplateSelector" />
</Page.Resources>
<Grid>
<ListView x:Name="myListView" ItemTemplateSelector="{StaticResource myPremiumUserDataTemplateSelector}">
</ListView>
</Grid>
</Page>
And my xaml.cs code is this
public sealed partial class ChatMessages : Page
{
public ChatMessages()
{
this.InitializeComponent();
List<chat> users = new List<chat>();
for (int i = 0; i < 10; ++i)
{
var user = new chat { NewMessages = "Name is mj "};
if (i == 2 || i == 4)
{
user.Name = "Alex Doe";
}
users.Add(user);
}
myListView.ItemsSource = users;
}
private void BackButton_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(InboxChat));
}
}
And my MyDataTemplateSelector class is this
public class MyDataTemplateSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
FrameworkElement elemnt = container as FrameworkElement;
chat user = item as chat;
if (user.Name == "Alex Doe")
{
return elemnt.FindName("leftTemplate") as DataTemplate;
}
else
{
return elemnt.FindName("rightTemplate") as DataTemplate;
}
}
}
I tried to use dummy values. And i have tried for hours.. but i could not find a solution. Please help me to solve this problem.
Thank you very much!!
I think you need to pass the data templates to the selector when it is initialized in the view XAML. Here is how to do it.
You selector will look like this (basically accepting the data templates as properties in the class):
public class MyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DataTemplate1 { get; set; }
public DataTemplate DataTemplate2 { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
if ([Condition 1] == true)
return DataTemplate1;
if ([Condition 2] == true)
return DataTemplate2;
return base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return SelectTemplateCore(item);
}
}
Then to use this selector, declare it like this in your view's XAML:
<Page.Resources>
<MyDataTemplateSelector x:Key="MySelector">
<MyDataTemplateSelector.DataTemplate1>
<DataTemplate .... />
<MyDataTemplateSelector.DataTemplate1>
<MyDataTemplateSelector.DataTemplate2>
<DataTemplate .... />
<MyDataTemplateSelector.DataTemplate2>
</MyDataTemplateSelector>
</Page.Resources>
you will basically be declaring those data templates inside the xaml code initializing your selector.
Edit: As for the reason your code wasn't working: I suspect this is because it can't find the element you are looking for with FindName and is probably returning a null data template back to the list view using this selector.
Hope this helps you.
This app is displaying the class name of a collection instead of a text-box as desired. I've read other issues with this, but cannot figure out what I'm missing. I have a datacontext, I'm bound to the collection as an itemsource, and I've added a single item. All I want is to bind the collection 'Boxes' in my view model 'DrawBoxViewModel' to an item source, and have it display a single item as a text box. All help is appreciated.
First my XAML:
<Page
x:Class="BoxMaker2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BoxMaker2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:BoxMaker2.ViewModels"
mc:Ignorable="d">
<Page.Resources>
<vm:DrawBoxViewModel x:Key="DrawBoxViewModel"/>
</Page.Resources>
<Canvas DataContext="{Binding Source={StaticResource DrawBoxViewModel}}">
<ItemsControl ItemsSource="{Binding Boxes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Width="350" Height="600" Background="AliceBlue"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<DataTemplate x:DataType="vm:Box" x:Key="test">
<VariableSizedWrapGrid>
<TextBox Background="White"
Text="{x:Bind Data}"
Width="100"
Height="100"/>
<VariableSizedWrapGrid.RenderTransform>
<TranslateTransform X="{Binding LeftCanvas}" Y="{Binding TopCanvas}"/>
</VariableSizedWrapGrid.RenderTransform>
</VariableSizedWrapGrid>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
</Canvas>
And now my viewmodel:
namespace BoxMaker2.ViewModels
{
public class DrawBoxViewModel
{
#region fields
private ObservableCollection<Box> _boxes;
#endregion
#region properties
public ObservableCollection<Box> Boxes { get { return this._boxes; } }
#endregion
#region constructors
public DrawBoxViewModel()
{
this._boxes = new ObservableCollection<Box>();
_boxes.Add(new Box() { Data = "hello!", LeftCanvas = 200, TopCanvas = 200 });
}
#endregion
}
public class Box : INotifyPropertyChanged
{
private int _generation;
public int Generation
{
get { return _generation; }
set { _generation = value; OnPropertyChanged("Generation"); }
}
private int _childNo;
public int ChildNo
{
get { return _childNo; }
set { _childNo = value; OnPropertyChanged("ChildNo"); }
}
private Box _parentBox;
public Box ParentBox
{
get { return _parentBox; }
set { _parentBox = value; OnPropertyChanged("ParentBox"); }
}
private List<Box> _childrenBox;
public List<Box> ChildrenBox
{
get { return _childrenBox; }
set { _childrenBox = value; OnPropertyChanged("ChildrenBox"); }
}
private string _data;
public string Data
{
get { return _data; }
set
{
_data = value;
OnPropertyChanged("Data");
}
}
private double _topCanvas;
public double TopCanvas
{
get { return _topCanvas; }
set
{
_topCanvas = value;
OnPropertyChanged("TopCanvas");
}
}
private double _leftCanvas;
public double LeftCanvas
{
get { return _leftCanvas; }
set
{
_leftCanvas = value;
OnPropertyChanged("LeftCanvas");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I am not exactly sure what you are trying to achieve but here's a few issues I have found in your code.
You should assign your VM to the DataContext of the Page
directly.
<Page.DataContext>
<vm:DrawBoxViewModel />
</Page.DataContext>
After doing so, you can now remove DataContext="{Binding
Source={StaticResource DrawBoxViewModel}}" from your Canvas.
Replace <ItemsControl.Resource> with
<ItemsControl.ItemTemplate> and remove x:Key="test", assuming you want to show multiple
TextBoxes on the UI. The DataTemplate within the Resource you
defined won't do anything until you reference it by its key. I don't
think you really want that here though.
You should use x:Bind for your X & Y binding
<TranslateTransform X="{x:Bind LeftCanvas}"
Y="{x:Bind TopCanvas}" />
Your Boxes collection can be simplified as following
#region properties
public ObservableCollection<Box> Boxes { get; } = new ObservableCollection<Box>();
#endregion
#region constructors
public DrawBoxViewModel()
{
Boxes.Add(new Box() { Data = "hello!", LeftCanvas = 0, TopCanvas = 200 });
}
#endregion
Hope this helps!
Your Items control doesn't know which data template to use. Currently your view model has a template associated to it via the x:DataType="vm:Box" which is defined as a resource in the items control.
The problem is that Universal Windows Platform doesn't recognize templates associated to data types. So even though there is a template, the control doesn't know how to find it when it is rendering the collection of view models.
Automatic resolving of templates based on bound types was a function of WPF which is not available in UWP.
What that means is that in WPF you could associate a data template to a class/object via the x:DataType="Object Type" attribute of the data template (which is what you did). When the collection is bound, the rendering engine would auto-magically match the the individual items in the collection to their respective templates.
This was very powerful because if your collection had many different types of boxes for example (or things inheriting from DrawBoxViewModel) you could render each item type differently by simply defining a template. Well this is no more. Microsoft destroyed that feature in UWP.
So long story short - move the template to the page resource collection. Give it a key such as:
<Page.Resources>
<vm:DrawBoxViewModel x:Key="DrawBoxViewModel"/>
<DataTemplate x:Key="test">
<VariableSizedWrapGrid>
<TextBox Background="White"
Text="{x:Bind Data}"
Width="100"
Height="100"/>
<VariableSizedWrapGrid.RenderTransform>
<TranslateTransform X="{Binding LeftCanvas}" Y="{Binding TopCanvas}"/>
</VariableSizedWrapGrid.RenderTransform>
</VariableSizedWrapGrid>
</DataTemplate>
</Page.Resources>
Reference the template in your items control as follows:
<ItemsControl ItemsSource="{Binding Boxes} ItemTemplate={StaticResource test} ">
I have a class defined like:
public class Agent
{
public int Id { get; set; }
public string Category { get; set; }
// rest removed for brevity
}
Then, in WPF, I get the data as List and pass it to DataContext as this:
List<Agent> agents; // this includes my data
this.DataContext = agents;
And in .xaml part I want to list the Category field of each object. I have something like this:
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
Grid.Column="1"
ItemSource="{Binding Path=Category"} />
But this doesn't seem to work correctly. Any ideas?
Let me help you to do this in the correct way as Alex suggested.
Create a list and populate it in ViewModel like this
ViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
agents = new ObservableCollection<Agent>();
LoadData();
}
private void LoadData()
{
agents.Add(new Agent { Id = 1, Category = "a" });
agents.Add(new Agent { Id = 2, Category = "b" });
agents.Add(new Agent { Id = 3, Category = "c" });
}
}
In XAML, Make your list and use data template like this:
<Window.Resources>
<DataTemplate x:Key="AItemTemplate">
<TextBlock Text="{Binding Category}"></TextBlock>
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource="{Binding agents}"
ItemTemplate="{StaticResource AItemTemplate}"></ListBox>
That is it !!
Normally the DataContext would be a view model class that would contain the list of agents; then you can bind the ItemsSource to that list. Any of the many examples that deal with listbox will be pretty straight forward when it comes to that. Not really sure how the binding should look like if the list itself is the DataContext.
Then once the ItemsSource is set to a list of agents, if you want to show the Category in the list, the simpler way is to set DisplayMemberPath to "Category".
I suggest looking into MVVM and learning to apply it, it's an invaluable concept in my opinion.
You try to bind your listbox to a string property.
You can try this :
Give a name to your user control for exemle myUC
Add a property to your user control :
public List<Agent> AgentList { get; set; };
Fill your agentlist :
this.AgentList = //fill method
And bind your listbox like this :
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
Grid.Column="1"
ItemSource="{Binding Path=AgentList, ElementName=myUC"} />
may be this will give you an idea:
http://www.c-sharpcorner.com/forums/wpf-datacontext-binding-with-listbox
The fastest way to get what you want is :
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
DisplayMemberPath="Category"
Grid.Column="1"
ItemSource="{Binding Path=."} />
ItemsSource is binded directly to your Datacontext (which is your list) And then you tell to your ListBox to display the property Category.
But the proper way would have been :
1 - Create a DataContext
public class AgentsDC
{
public List<Agent> Agents { get; set; }
}
2 - Give this class as DataContext
this.DataContext = new AgentsDC();
3 - Bind all these things
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
DisplayMemberPath="Category"
Grid.Column="1"
ItemSource="{Binding Path=Agents"} />
I also would suggest you to use MVVM. But if you do not want to then try this.
XAML:
<ListBox Name="AgentCategoryListBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Category}" d:DataContext="{d:DesignData}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
CS:
public MainWindow()
{
InitializeComponent();
List<Agent> agents = new List<Agent>
{
new Agent
{
Category = "Category"
}
};
DataContext = agents;
}
public class Agent
{
public string Category
{
get;
set;
}
}
I'm trying to get the databinding I need to work with a ListBox.
I've parsed some data from a text file to a ObservableCollection<ViewModel> but the data isn't updating in the ListBox.
Here's some information:
The data which is written to from the parser:
class MainData
{
private static ObservableCollection<GroupViewModel> groupModelList = new ObservableCollection<GroupViewModel>();
public static ObservableCollection<GroupViewModel> GroupModelList
{
get { return groupModelList; }
}
}
What GroupViewModel holds (not everything but it's all the same):
class GroupViewModel : INotifyPropertyChanged
{
private GroupModel groupModel;
public event PropertyChangedEventHandler PropertyChanged;
public GroupViewModel()
{
groupModel = new GroupModel();
}
public string Name
{
get { return groupModel.name; }
set
{
if (groupModel.name != value)
{
groupModel.name = value;
InvokePropertyChanged("Name");
}
}
}
...
}
And what GroupModel Holds:
class GroupModel
{
public string name { get; set; }
}
This is how the parser adds new items to the GroupModelView:
if (split[0] == "group")
{
currentGroup = new GroupViewModel();
currentGroup.Name = split[1];
MainData.GroupModelList.Add(currentGroup);
}
I created a ListBox in my WPF application with these XAML options:
<Window x:Class="SoundManager.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:SoundManager.ViewModels"
xmlns:vm2="clr-namespace:SoundManager.Code"
Title="MainWindow" Height="720" Width="1280">
<Window.Resources>
<vm:MainViewModel x:Key="MainViewModel" />
<vm2:MainData x:Key="MainData" />
</Window.Resources>
<ListBox Grid.Row="2" Height="484" HorizontalAlignment="Left" Margin="12,0,0,0" Name="lbFoundItems" VerticalAlignment="Top" Width="201" ItemsSource="{Binding Source={StaticResource MainData}, Path=GroupModelList/Name}" />
but for some reason the data isn't updating in the UI (new items aren't added visibly in the UI).
I've been just getting started with the MVVM pattern and databinding and I can't figure out what I'm doing wrong.
Thanks in advance!
GroupModelList/Name is not a valid property path here. Setting it like that does not make the ListBox show the Name property of the data items in the GroupModelList collection.
You would instead have to set the ListBox's DisplayMemberPath property:
<ListBox ItemsSource="{Binding Source={StaticResource MainData}, Path=GroupModelList}"
DisplayMemberPath="Name"/>
or set the ItemTemplate property:
<ListBox ItemsSource="{Binding Source={StaticResource MainData}, Path=GroupModelList}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Moreover, the GroupModelList property should not be static:
class MainData
{
private ObservableCollection<GroupViewModel> groupModelList =
new ObservableCollection<GroupViewModel>();
public ObservableCollection<GroupViewModel> GroupModelList
{
get { return groupModelList; }
}
}
Then you might have MainData as a property in your view model, and bind the ListBox like this:
<ListBox ItemsSource="{Binding Source={StaticResource MainViewModel},
Path=MainData.GroupModelList}" .../>