My XAML is as under. I have a main ViewModel which has a list of items and I want to display a property within this list
<ItemsControl ItemsSource="{Binding MyList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding MyName, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"></Label>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The problem is that MyName is always blank although my list has two items.
The main VM class has this property below and I add items in the constructor
public ObservableCollection<InnerViewModel> MyList { get; set; }
My inner VM has
public class InnerViewModel
{
private string _MyName;
public string MyName
{
get
{
return _MyName;
}
set
{
_MyName = value;
OnPropertyChanged("MyName");
}
}
I do have OnPropertyChanged in place but I'm not pasting it here for simplicity. I think the problem is with the XAML but I'm not sure. How do I get the property MyName to be displayed in my list of items in the view?
Since you use MyList as the ItemsSource, the data source for the child elements will be MyList. So you do not need to use the RelativeSource.
In other words, this should work :
<ItemsControl ItemsSource="{Binding MyList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding MyName}"></Label>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Try and remove the relative source part of the binding.
<DataTemplate>
<Label Content="{Binding MyName}"></Label>
</DataTemplate>
Related
I have a little problem and I don't know how to fix it.
In my View I have a combobox, that should be able to display the property "Name" of the ObservableCollection "Phases". I already tried to show a single "Name-property" without a Datatemplate and it worked. I think I messed something up with the binding in the DataTemplate. What is wrong? Can you help me?
Here is my View:
<ComboBox ItemsSource="{Binding Phases}"
SelectedItem=""
Width="100" HorizontalAlignment="Left"
Margin="50,20">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Here my ObservableCollection:
public ObservableCollection<PhaseViewModel> Phases
{
get;
}
And here the property inside Phases:
public string Name
{
get { return myName; }
set { myName = value;}
}
I have a table with checkboxes that is bound to the ObservableCollection > collection, I want to track changes to this collection when one of the checkboxes changes my view.
This is my code:
<UserControl.Resources>
<DataTemplate x:Key="DataTemplate_Level2">
<CheckBox IsChecked="{Binding Path=. ,Mode=TwoWay}" Height="40" Width="50" Margin="4,4,4,4"/>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_Level1">
<ItemsControl x:Name="2st" Items="{Binding Path=. ,Mode=TwoWay}" ItemTemplate="{DynamicResource DataTemplate_Level2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</UserControl.Resources>
<ItemsControl Grid.Column="1" Items="{Binding MyCollection, Mode=TwoWay}" x:Name="lst" ItemTemplate="{DynamicResource DataTemplate_Level1}" Background="Gold"/>
My viewModel property
public ObservableCollection<ObservableCollection<bool>> MyCollection
{
get
{
return someCollection;
}
set
{
someCollection = value;
RaisePropertyChanged(nameof(MyCollection));
}
}
view of table
How Can I pass collection data changes to view model?
You need to declare a new class that will become viewmodel for checkbox with property of type book and proper RaisePropertyChanged invoking. And MyCollection must be collection of collections of instances of that class rather than bool
public class CheckboxViewModel
{
private bool _checkboxValue;
public bool CheckboxValue
{
get
{
return _checkboxValue;
}
set
{
_checkboxValue = value;
RaisePropertyChanged(nameof(CheckboxValue));
}
}
}
Make sure you have two-way binding in checkbox view to that property
BTW - RaisePropertyChanged at setter of MyCollection raises event with wrong property name in you example.
My class looks like this:
public class testclass
{
public List<otherClass> references { get { return _references; } }
}
My otherClass looks like this
public class otherClass
{
public string name { get; set; }
}
And now i try to access this "otherClass" inside a DataTemplate
<DataTemplate x:Key="templateCore" DataType="{x:Type vm:AdminInterfaceViewModel}" >
<GroupBox DataContext="{Binding references }">
...
</DataTemplate>
this works fine, or i think at least, beaucse intellisense autocomplete it. But now how can i get access to the name property of the "otherClass" ?
All you need is to binding the List to a ItemsControl type,such as ListBox,DataGrid etc,and the ItemsControl will use the 'otherClass' instance in the List as the DataContext for each item in it.So you can find a 'mapping' there:
'List<otherClass>'--'ItemsControl'
'otherClass'--'Item'
.
I suppose that 'AdminInterfaceViewModel' is your DataContext,and 'references' is one property of it, so try this:
<DataTemplate x:Key="templateCore" DataType="{x:Type vm:AdminInterfaceViewModel}" >
<GroupBox>
<ListBox ItemsSource="{Binding references}">
<ListBox.ItemTemplate>
<DataTemplate>
<TexBox Text="{Binding name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
</DataTemplate>
> Update:
1.Suppose that you have a MainViewModel which contains a property named MyViewModel in type of 'AdminInterfaceViewModel '.
class MainViewModel
{
public AdminInterfaceViewModel MyViewModel {get; set;}
}
2.You have set the 'MainViewModel' as the DataContext of your Window,then you can use the property 'MyViewModel' in xaml.
<Window>
<Grid>
<ContentControl Margin="20" Content="{Binding MyViewModel}">
</ContentControl>
</Grid>
</Window>
3.Define the DataTemplate in your ResourceDictionary such as 'generic.xaml'.Remove the x:Key then the DataTemplate will automatically applied to every 'AdminInterfaceViewModel' type instance.
<DataTemplate x:Key="templateCore" DataType="{x:Type vm:AdminInterfaceViewModel}" >
<GroupBox>
<ListBox ItemsSource="{Binding references}">
<ListBox.ItemTemplate>
<DataTemplate>
<TexBox Text="{Binding name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
</DataTemplate>
> Tips:
Check this link,it may solve your potential problems:MVVM pattern
I'm writing simple WPF Application and I wanted to use ListView to display List of items. My code is:
WPF.xaml
<ListView Grid.Column="0" Grid.Row="1" Margin="10,0,10,5" ItemsSource="{Binding MyCollection.Elements}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ElementDescriptions}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
WPF.xaml.cs
public MyViewModel ViewModel
{
get { return DataContext; }
set { DataContext = value; }
}
MyViewModel.cs
public OwnedCollection Elements { get; set; }
OwnedCollection.cs
public List<ElementDescriptions> ElementDescriptions { get; set; }
I'm 100% sure, that communication between View and ViewModel is correct, because displaying simple message doesn't make me troubles. Am I doing right binding in ListView?
A couple things:
First,
TextBlock Text="{Binding ElementDescriptions}"
doesn't make a lot of sense because ElementDescriptions is a collection. If you want to loop through all the ElementDescriptions in your List you should really be binding the ItemSource of the ListView to ElementDescriptions then accessing some text property of the ElementDescriptions class:
<ListView Grid.Column="0" Grid.Row="1" Margin="10,0,10,5" ItemsSource="{Binding MyCollection.ElementsElementDescriptions }">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ElementDescriptions.SomeTextField}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Second, are you using INotifyPropertyChanged so the view knows to update? More info on that here: OnPropertyChanged with a List
I am trying to bind a list of string values to a listbox so that their values are listed line by line. Right now I use this:
<ListBox Margin="20" ItemsSource="{Binding Path=PersonNames}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Id}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But I don't know what I am supposed to put into the textblock, instead of Id, since they are all string values, not custom classes.
Also it complains not having to find the PersonNames when I have it inside MainPage, as MainPage.PersonNames.
I set the data context to:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
I am doing it wrong?
If simply put that your ItemsSource is bound like this:
YourListBox.ItemsSource = new List<String> { "One", "Two", "Three" };
Your XAML should look like:
<ListBox Margin="20" Name="YourListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Update:
This is a solution when using a DataContext. Following code is the viewmodel you will be passing to the DataContext of the page and the setting of the DataContext:
public class MyViewModel
{
public List<String> Items
{
get { return new List<String> { "One", "Two", "Three" }; }
}
}
//This can be done in the Loaded event of the page:
DataContext = new MyViewModel();
Your XAML now looks like this:
<ListBox Margin="20" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The advantage of this approach is that you can put a lot more properties or complex objects in the MyViewModel class and extract them in the XAML. For example to pass a List of Person objects:
public class ViewModel
{
public List<Person> Items
{
get
{
return new List<Person>
{
new Person { Name = "P1", Age = 1 },
new Person { Name = "P2", Age = 2 }
};
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
And the XAML:
<ListBox Margin="20" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=Age}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You should show us the code for PersonNames, and I am not sure I understand your question, but maybe you want to bind it like this:
<TextBlock Text="{Binding Path=.}"/>
or
<TextBlock Text="{Binding}"/>
This will bind to the current element in the list (assuming PersonNames is a list of strings). Otherwise, you will see the class name in the list.
If the items source is enumerable as string-entries, use the following:
<TextBlock Text="{Binding}"></TextBlock>
You can use this syntax on any object. Generally, the ToString() -method will then called to get the value. This is in many cases very handy. But beware that no change notification will occur.
You can do this without having to explicitly define the TextBlock control as a part of your ListBox (unless you want better formatting). The trick to getting the binding to trigger is using an ObservableCollection<string> instead of List<string>
Window1.xaml
<ListView Width="250" Height="50" ItemsSource="{Binding MyListViewBinding}"/>
Window1.xaml.cs
public Window1()
{
InitializeComponent();
DataContext = this;
// Need to initialize this, otherwise you get a null exception
MyListViewBinding = new ObservableCollection<string>();
}
public ObservableCollection<string> MyListViewBinding { get; set; }
// Add an item to the list
private void Button_Click_Add(object sender, RoutedEventArgs e)
{
// Custom control for entering a single string
SingleEntryDialog _Dlg = new SingleEntryDialog();
// OutputBox is a string property of the custom control
if ((bool)_Dlg.ShowDialog())
MyListViewBinding.Add(_Dlg.OutputBox.Trim());
}