I have a ListView which binds each list view item to a Class A which has a List
<Page
DataContext="{Binding MainViewModel , Source={StaticResource Locator}}"
>
<ListView ItemsSource="{Binding A.List}" >
<ListView.ItemTemplate>
....
</ListView.ItemTemplate>
</ListView>
</Page>
And in my ViewModel, I have the class 'A' and it has a property List
public class MainViewModel : ViewModelBase {
private A _a;
public A A {
get {
return _a;
}
}
}
public class A
{
private IList<IList> _lists;
IList<int> List {
get {
return _lists;
};
set {
_lists = value;
RaisePropertyChanged("List");
}
}
In the set() method I has called 'RaisePropertyChanged()' whenever the List is set.
But when I run it, the ListView content does not get update.
Should I raise RaisePropertyChanged("List") or RaisePropertyChanged("A.List") (like what I put in {Binding A.List] in my xaml? In my case, I set the List to another instance of a List.
Try this see if it works.
public class A : INotifyPropertyChanged
{
private IList<int> _lists;
IList<int> List {
get {
return _lists;
};
set {
_lists = value;
OnPropertyChanged("List");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Related
I have a ComboBox in my View:
<ComboBox Name="comboBox1" ItemsSource="{Binding MandantList}" SelectedItem="{Binding CurrentMandant, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Firma}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Here is my Model:
public class MandantListItem : INotifyPropertyChanged
{
public MandantListItem() { }
string _Firma;
bool _IsChecked;
public string Firma
{
get { return _Firma; }
set { _Firma = value; }
}
public bool IsChecked
{
get
{
return _IsChecked;
}
set
{
_IsChecked = value;
OnPropertyChanged(nameof(IsChecked));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
And here is my ViewModel:
public class MaViewModel : INotifyPropertyChanged
{
public ObservableCollection<MandantListItem> MandantList { get { return _MandantList; } }
public ObservableCollection<MandantListItem> _MandantList = new ObservableCollection<MandantListItem>();
private MandantListItem _CurrentMandant;
public MandantListItem CurrentMandant
{
get { return _CurrentMandant; }
set
{
if (value != _CurrentMandant)
{
_CurrentMandant = value;
OnPropertyChanged("CurrentMandant");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
How to fill the ComboBox:
public zTiredV2.ViewModel.MaViewModel MAList = new zTiredV2.ViewModel.MaViewModel();
this.comboBox1.ItemsSource = MAList.MandantList;
MAList.MandantList.Add(new zTiredV2.Model.MandantListItem { Firma = "A", Homepage = "a.com", IsChecked = false });
MAList.MandantList.Add(new zTiredV2.Model.MandantListItem { Firma = "B", Homepage = "b.com", IsChecked = false });
But my item doesnt update ... tried also via IsChecked, but no success either ... when i iterate through MAList, IsChecked is always false. And how can i bind a TextBlock to the selected Firma?
Have a hard time with MVVM, but i like it.
You should set the DataContext of the ComboBox to an instance of your view model. Otherwise the bindings won't work:
this.comboBox1.DataContext = MAList;
Also note that the _MandantList backing field for your property shouldn't be public. In fact, you don't need it at all:
public ObservableCollection<MandantListItem> MandantList { get; } = new ObservableCollection<MandantListItem>();
Setting the DataContext should cause the CurrentMandant property to get set when you select an item in the ComboBox. It won't set the IsChecked property though.
I kinda stuck on data-binding here. So, let's say I have a following Class :
Student.cs
public class Student : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string _name;
public string Name
{
get { return _name; }
set { _name = value; NotifyPropertyChanged("Name");
}
public bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set { _isSelected = value; NotifyPropertyChanged("IsSelected");
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then, I have a UserControl to visualize the class, with the following ViewModel :
StudentVisualizerVM.cs
public class StudentVisualizerVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Student _student;
public Student Student
{
get { return _student; }
set { _student = value ; NotifyPropertyChanged("Student"); }
}
public StudentVisualizerVM()
{
Student = new Student();
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And then, I want to use the UserControl in my MainWindow.
MainWindow.Xaml
<ItemsControl Grid.Column="0" Grid.Row="0" ItemsSource="{Binding Student}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<c:StudentVisualizer/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And finally this is my MainWindow ViewModel look like :
MainWindowVM.cs
public class MainWindowVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Student _student;
public Student Student
{
get { return _student; }
set { _student = value ; NotifyPropertyChanged("Student"); }
}
public MainWindowVM()
{
Student = new Student();
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The problem is that the User Control didn't shows up on MainWindow even though I had initialize the Student Property in MainWindow. Why? Isn't MVVM User Control automatically populate its ViewModel? Or maybe it's StudentVisualizerVM that I need to store in MainWindowVM, instead of the Student itself?
Note That (Updated) :
Above code is not the real one, it's just to simplify my project into the main problem.
Assume each XAML's DataContext has been attached correctly from the XAML.CS.
Why I need to do this? Because I need to detect if the window has been clicked outside the StudentVisualizer then IsSelected is set to false. (This property used for certain Command which need the Student to be selected.) - Something like Select-Deselect-esque actio.
ItemsControl is for displaying a collection of items, therefore ItemsControl.ItemsSource has to bind to an IEnumerable property, while you just bind to a single element.
You want something like :
ItemsSource="{Binding StudentCollection}"
public IEnumerable<Student> StudentCollection
{
get { return new List<Student> { Student }; }
}
Now, should you really use an ItemsControl to display just one item.. that's another question and the answer would be : no.
I am unable figure out why the databinding is not working as expected:
I created a Listbox and set its ItemSource to my observable collection
I used this.DataContext = this
I Initialized my public Observable Collection
I filled it with objects that implement INotifyPropertyChanged
Yet, the databinding, still does not work. My Listbox:
<ListBox Height="425" ItemsSource="{Binding headers}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=HeaderInfo}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The code behind:
public partial class cornet_controls : PhoneApplicationPage
{
public ObservableCollection<headerInfo> headers;
public cornet_controls()
{
InitializeComponent();
this.DataContext = this;
headers = new ObservableCollection<headerInfo>();
for (int x = 0; x < 100; x++)
headers.Add((new headerInfo() { HeaderInfo = x.ToString() }));
}
}
My custom class implementing INotifyPropertyChanged:
public class headerInfo : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public headerInfo()
{}
private String _HeaderInfo;
public String HeaderInfo
{
get { return _HeaderInfo; }
set { _HeaderInfo = value; NotifyPropertyChanged("HeaderInfo"); }
}
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You cannot bind to a NonProperty:
<ListBox Height="425" ItemsSource="{Binding headers}">
public ObservableCollection<headerInfo> headers;
you need to bind to a Property like:
public ObservableCollection<headerInfo> headers { get; set; }
I have a problem with my Binding to a ListBox Control.
Actually i have a Property in App.xaml.cs :
public partial class App : Application, INotifyPropertyChanged
{
ObservableCollection<Panier> _panier = new ObservableCollection<Panier>();
public ObservableCollection<Panier> PanierProperty
{
get { return _panier; }
set
{
if (this._panier != value)
{
this._panier = value;
NotifyPropertyChanged("PanierProperty");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
this property have a child properties in the "Panier class" here:
public class Panier : INotifyPropertyChanged
{
private string _nom;
private string _category;
private int _prix;
public string Nom
{
get { return _nom; }
set
{
if (this._nom != value)
{
this._nom = value;
NotifyPropertyChanged("Nom");
}
}
}
public string Category
{
get { return _category; }
set
{
if (this._category != value)
{
this._category = value;
NotifyPropertyChanged("Category");
}
}
}
public int Prix
{
get { return _prix; }
set
{
if (this._prix != value)
{
this._prix = value;
NotifyPropertyChanged("Prix");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
and in my MainWindow.xaml page i have my ListBox bound to PanierProperty(parent property) :
<telerik:RadListBox x:Name="PanierLB" Grid.Row="1" Height="200" Width="350" Margin="0 300 0 0"
ItemsSource="{Binding PanierProperty, Source={x:Static Application.Current}}"
DisplayMemberPath="{Binding Path=PanierProperty.Nom, Source={x:Static Application.Current}}">
</telerik:RadListBox>
my problem is that PanierProperty is bound to my Listbox i see items in the listbox like Design.Panier
Design.Panier
Design.Panier
etc...
I dont know how to get the PanierProperty.Nom(Nom is the child property) to show on the ListBox.
Someone can help please.
In DisplayMemberPath use the name of property you want to show only:
<telerik:RadListBox
...
DisplayMemberPath="Nom"
In my user control I have this property:
public static DependencyProperty FooListProperty = DependencyProperty.Register(
"FooList", typeof(List<Problem>), typeof(ProblemView));
public List<Problem> FooList
{
get
{
return (List<Problem>)GetValue(FooListProperty);
}
set
{
SetValue(FooListProperty, value);
}
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == FooListProperty)
{
// Do something
}
}
And since another window, I´m trying to set a value for the last user control:
<local:ProblemView HorizontalAlignment="Center"
VerticalAlignment="Center" FooList="{Binding list}" />
And that window in load contains:
public List<Problem> list;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Some processes and it sets to list field
list = a;
}
But in XAML code, binding it isn't working. Don't pass the data. What am I wrong?
You can't bind to a Field in WPF, you'll have to change list to a property instead.
You call the Dependency Property FooList in your UserControl and ResultList in Xaml but I'm guessing that's a typo in the question.
You should implement INotifyPropertyChanged in the Window to let the Bindings know that the value has been updated.
I'm not sure if you have the correct DataContext set in the Xaml ProblemView, if you're unsure you can name the Window and use ElementName in the binding
<Window Name="window"
...>
<!--...-->
<local:ProblemView HorizontalAlignment="Center"
VerticalAlignment="Center"
ResultList="{Binding ElementName=window,
Path=List}" />
<!--...-->
</Window>
Sample code behind
public partial class MainWindow : Window, INotifyPropertyChanged
{
//...
private List<Problem> m_list;
public List<Problem> List
{
get { return m_list; }
set
{
m_list = value;
OnPropertyChanged("List");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}