Binding constant Collection to ComboBox & SelectedItem to TextBox - c#

I'm new to MVVM in WPF and I have the following problem.
What I try to have is two ComboBoxes, each binding to the same ObservableCollection<TwoProperties> DList property as ItemsSource and with synchronized SelectedItem, so I wrote this in my XAML
<ComboBox ItemsSource="{Binding DList}" DisplayMemberPath="Property1" SelectedItem="{Binding SelectedD}" />
<ComboBox ItemsSource="{Binding DList}" DisplayMemberPath="Property2" SelectedItem="{Binding SelectedD}" />
with this viewmodel
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<TwoProperties> _dList =
new ObservableCollection<TwoProperties> {
new TwoProperties(1,"one"),
new TwoProperties(2,"two")
};
public ObservableCollection<TwoProperties> DList
{
get { return _dList; }
set { _dList = value; OnPropertyChanged("DList"); }
}
private TwoProperties _selectedD;
public TwoProperties SelectedD
{
get { return _selectedD; }
set { _selectedD = value; OnPropertyChanged("SelectedD"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
where
public class TwoProperties
{
public double Property1 { get; set; }
public string Property2 { get; set; }
public TwoProperties (double p1, string p2)
{
Property1 = p1;
Property2 = p2;
}
}
I would also like to have two TextBoxes that display the properties of the currently SelectedItem of the synchronized ComboBoxes. The properties Property1 and Property2 of SelectedD should be editable, however the ObservableCollection<TwoProperties> _dList should remain constant/readonly and not change its values.
<TextBox Text="{Binding SelectedD.Property1}" />
<TextBox Text="{Binding SelectedD.Property2}" />
But when I edit the TextBoxes and therefore SelectedD, also _dList changes its values, which is not what I want.
I hope I could explain my problem. I'm sure I'm missing something simple here.

This could be implemented easily by changing the binding mode for the TextBoxes into one way as following:
<TextBox Text="{Binding SelectedD.Property1,Mode=OneWay}" />
<TextBox Text="{Binding SelectedD.Property2,Mode=OneWay}" />
Thus when you change the textBox value, the changes would not be reflected back to the Observable collection objects.
Note that you can get rid of magical strings in your view model OnPropertyChanged by modifying the method as following:
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
And then you can call it inside the setter of any property inside the view model without passing the name of the property as following:
private TwoProperties _selectedD;
public TwoProperties SelectedD
{
get { return _selectedD; }
set { _selectedD = value; OnPropertyChanged(); }
}
Edit 2:
Update my binding and view model to get the edited values inside the view model
View model updates:
private double? editPropertyOne;
public double? EditPropertyOne
{
get { return editPropertyOne; }
set
{
editPropertyOne = value;
OnPropertyChanged();
}
}
private string editPropertyTwo;
public string EditPropertyTwo
{
get { return editPropertyTwo; }
set
{
editPropertyTwo = value;
OnPropertyChanged();
}
}
private TwoProperties _selectedD;
public TwoProperties SelectedD
{
get { return _selectedD; }
set
{
_selectedD = value; OnPropertyChanged();
if (_selectedD != null)
{
EditPropertyOne = _selectedD.Property1;
EditPropertyTwo = _selectedD.Property2;
}
}
}
Xaml changes:
<TextBox Text="{Binding EditPropertyOne}" />
<TextBox Text="{Binding EditPropertyTwo}" />

Related

Data Binding Issue: How do I get the Binding value to work both ways?

I am working on a MVVM WPF application and I have a CheckBox which I am trying to work on. What I want is for the value to be binding to a model property (which I have done). However, when I click it in a debugging session it never actually changes my IsChecked property to true from its default false. Please see code below:
Model
public class MyModel:INotifyPropertyChanged
{
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
if (_isChecked == value)
return;
_isChecked = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
View
<StackPanel Orientation="Horizontal" Height="51" Width="667" Canvas.Left="10" Canvas.Top="45">
<CheckBox IsChecked="{Binding IsChecked}" Command="{Binding CheckBoxClickCommand}" Content="We're in the matrix" VerticalAlignment="Center" Margin="10,10,200,10"/>
</StackPanel>
ViewModel
public class MyViewModel
{
private MyModel _myModel = new MyModel();
public ObservableCollection<MyModel> UrlsList { get; } = new ObservableCollection<MyModel>();
public ICommand CheckBoxClickCommand { get; private set; }
public MyViewModel()
{
CheckBoxClickCommand = new RelayCommand(CheckBoxOnClick);
}
public void CheckBoxOnClick()
{
var newList = new List<MyModel>();
if (_myModel.IsChecked)
{
foreach (var url in UrlsList)
{
if (!url.ExistsInDb)
newList.Add(url);
}
}
}
}
When I debug and get to the if statement in CheckBoxClickCommand it obviously goes to the model to get the property value, but it does not change from the default false to true. Any help is much appreciated, thanks!.
Bind to the model's property:
<CheckBox IsChecked="{Binding Model.IsChecked}" ...>
For this to work, the model has to be returned from a public property of the view model:
private MyModel _myModel = new MyModel();
public MyModel Model { get { return _myModel; }}

textbox input to get / set viewmodel

I'm sure this has already been asked, but I'm still new to MVVM and WPF, and not too sure what I should be searching for.
I have a viewmodel which includes items in a Model, as well as some additional temporary data items which will all be passed to a process.start(). I have a stackpanel of textbox, and want to allow the user to type in a "ModelName", and if existing, The ViewModel will get and set "TemplateName" associated with the ModelName.
I'm a bit lost on how to implement this. Do I need to create a completely separate ViewModel, which then goes and extracts data from ModelViewModel? Do I just write some code under ModelName's set, where it can validate, query, and set TemplateName?
Model:
public partial class Model
{
public string ModelName { get; set; }
public virtual Template Template { get; set; }
and ViewModel, which takes the Model, and some temporary data:
public class LauncherViewModel:ViewModelBase
{
public LauncherViewModel()
{
_ESTContext = new ESTContext();
Models = new ObservableCollection<Model>(_ESTContext.Models);
}
private ESTContext _ESTContext;
private string _modelname;
private string _serialno;
private string _sonumber;
private string _templatename;
private string _outputname;
private Model _selectedmodel;
public ObservableCollection<Model> Models { get; set; }
public string ModelName
{
get { return _modelname; }
set
{
if (!string.Equals(_modelname, value))
{
_modelname = value;
};
}
}
public string TemplateName { get { return _templatename; }}
public string SerialNo { get { return _serialno; } }
public string SONumber { get { return _sonumber; } }
public string OutputName { get { return _outputname; } }
public Model SelectedModel
{
get { return _selectedmodel; }
set
{
if (_selectedmodel != value)
{
_selectedmodel = value;
}
}
}
}
My View:
<DockPanel>
<StackPanel Margin="0,78,0,68" Width="233" DataContext="{Binding Models}">
<ComboBox IsEditable="True" Text="{Binding ModelName}" SelectedItem="{Binding SelectedModel}"/>
<TextBox Height="23" TextWrapping="Wrap" Text="{Binding SONumber}"/>
<TextBox Height="23" TextWrapping="Wrap" Text="{Binding SerialNumber}"/>
<Button Content="Button"/>
</StackPanel>
</DockPanel>
For your gui to update you must implement INotifyPropertyChanged and a call to it on all your bound properties.
// basic base class for your models, you a
public class ModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] // remove if you are not using R#
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
// your model
public class Model : ModelBase
{
private string modelName;
private Template template;
public string ModelName
{
get { return modelName; }
set
{
if (value == modelName) return;
modelName = value;
OnPropertyChanged();
}
}
public virtual Template Template
{
get { return template; }
set
{
if (Equals(value, template)) return;
template = value;
OnPropertyChanged();
}
}
}
View:
<DockPanel>
<StackPanel Margin="0,78,0,68" Width="233">
<ComboBox IsEditable="True" Text="{Binding ModelName, Mode='TwoWay'}" SelectedItem="{Binding SelectedModel}" ItemsSource="{Binding Models}"/>
<TextBox Height="23" TextWrapping="Wrap" Text="{Binding SONumber Mode='TwoWay'}"/>
<TextBox Height="23" TextWrapping="Wrap" Text="{Binding SerialNumber Mode='TwoWay'}"/>
<Button Content="Button"/>
</StackPanel>
Note the Mode='TwoWay' this makes the GUI change the values in your viewmodel, rather than just display them. So you need to set that on everything that's supposed to be editable as above. The default behaviour of WPF is that when a control looses focus it will update the bound property, if you set UpdateSourceTrigger='PropertyChanged' the property will be updated each time ie a letter is entered in a text box. I'll leave that part to you, but you will have to do it in your vm! At minimum the properties SONumber,SerialNumber and Models(if it's ref. changes).
VM: I assume you use galasoft here
public class LauncherViewModel : ViewModelBase
{
private ESTContext _ESTContext;
private string _templatename;
private string _modelname;
private string serialNumber;
private string _outputname;
private string modelName;
private ObservableCollection<Model> models;
private Model selectedModel;
private string soNumber;
public LauncherViewModel()
{
// dangerous ;)
_ESTContext = new ESTContext();
Models = new ObservableCollection<Model>(_ESTContext.Models);
}
public ObservableCollection<Model> Models
{
get { return models; }
set
{
if (Equals(value, models)) return;
models = value;
RaisePropertyChanged();
}
}
public string ModelName
{
get { return modelName; }
set
{
if (value == modelName) return;
modelName = value;
RaisePropertyChanged();
}
}
public string TemplateName { get { return _templatename; }}
public string SerialNumber // Note you spelled this wrong in your xaml. SONumber
{
get { return serialNumber; }
set
{
if (value == serialNumber) return;
serialNumber = value;
RaisePropertyChanged();
}
}
public string SONumber
{
get { return soNumber; }
set
{
if (value == soNumber) return;
soNumber = value;
RaisePropertyChanged();
}
}
public string OutputName { get { return _outputname; } }
public Model SelectedModel
{
get { return selectedModel; }
set
{
if (Equals(value, selectedModel)) return;
selectedModel = value;
RaisePropertyChanged();
}
}
}
A cool litle thing if you are using galasoft or sim together with R#.
public class YourViewModelBase : ViewModelBase
{
[NotifyPropertyChangedInvocator] // alt + enter = convert auto property to prop
// with backing field and change notification :)
override protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
base.RaisePropertyChanged(propertyName);
}
// .. :)
}
Cheers,
Stian
If I havent misunderstood your question , Bind Models to ItemsSource of ComboBox instead of Binding it to DataContext of StackPanel
Remove DataContext binding
<StackPanel Margin="0,78,0,68" Width="233" >
Bind Itemssource of ComboBox to Models and you will also have to specify DisplayMemberPath to the property of Model that you want to display in ComboBox.
<ComboBox IsEditable="True" ItemsSource="{Binding Models}" Text="{Binding ModelName}" SelectedItem="{Binding SelectedModel}"/>
And I am assuming you are setting DataContext of window to instance of LauncherViewModel class.
You need to raise the property changed event on properties you bind to i.e.:
private string _ModelName;
public string ModelName
{
get { return _ModelName; }
set
{
if (_ModelName != value)
{
_ModelName = value;
RaisePropertyChanged("ModelName");
}
}
}
In your base view model you need something like this (make sure you implement INotifyPropertyChanged):
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
In the constructor or loaded event of your view add this:
DataContext = new LauncherViewModel();

Binding Combobox Name using Id value

I have a combobox control. I am getting combobox values from Database. There I have Id and Name. But I am binding only Name in the combobox. what i want is,
1. If I select any name in the Combobox, I need to save the Corresponding Id in my Database. Now I am able to bind the value from database and Display the Name in Combobox. but when I select any value in combobox and try to save means, it shows null value on the ID. Here is my code. Please help me to find some solution.
Xaml:
<ComboBox x:Name="cb_rentaltype" HorizontalAlignment="Left" Margin="150,5,0,0" VerticalAlignment="Top" Height="35" Width="200"
SelectedValue="{Binding MasterRentalType}"
DisplayMemberPath="RentalTypeName"
SelectedValuePath="RentalTypeId" />
My code Behind:
var status = new MasterRentalType();
List<MasterRentalType> listRentalType =
status.Get<MasterRentalType>() as
List<MasterRentalType>;
cb_rentaltype.ItemsSource = listRentalType;
and i want to bind the Id to the Data context. here is the code,
private void FacilityDataBind()
{
cb_rentaltype.DataContext = ??
}
Note: MasterRentalType is the Table where i get the Values. There I have ID and Name values.
public class MasterRentalType : EntityBase
{
public string RentalTypeId {get; set;}
public string RentalTypeName {get; set;}
}
how can I bind and save the id value?
Your problem is caused because you have data bound the ComboBox.SelectedValue property to your MasterRentalType property, which I assume is of type MasterRentalType, but then you set the SelectedValuePath property to RentalTypeId. So you're saying *make the SelectedValue use the string RentalTypeId property, but then data binding a MasterRentalType to it.
There are a number of solutions. Correcting your example, you should try this:
<ComboBox x:Name="cb_rentaltype" HorizontalAlignment="Left" Margin="150,5,0,0"
SelectedValue="{Binding MasterRentalType.RentalTypeId}"
DisplayMemberPath="RentalTypeName"
SelectedValuePath="RentalTypeId" />
Alternatively, you could have done this:
<ComboBox x:Name="cb_rentaltype" HorizontalAlignment="Left" Margin="150,5,0,0"
SelectedItem="{Binding MasterRentalType}"
DisplayMemberPath="RentalTypeName" />
To find out more about the differences, please take a look at the How to: Use SelectedValue, SelectedValuePath, and SelectedItem page on MSDN.
There are several ways to achieve this. One of them is implemented below:
The xaml should look like this:
<ComboBox x:Name="cb_rentaltype" HorizontalAlignment="Left" Margin="150,5,0,0"
ItemsSource="{Binding MasterRentalTypeColl, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
SelectedItem="{Binding SelectedMasterRentalType, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
DisplayMemberPath="RentalTypeName">
</ComboBox>
The MasterRentalType class:
public class MasterRentalType : EntityBase, INotifyPropertyChanged
{
private string _RentalTypeId;
private string _RentalTypeName;
public string RentalTypeId
{
get { return _RentalTypeId; }
set
{
_RentalTypeId = value;
NotifyPropertyChanged("RentalTypeId");
}
}
public string RentalTypeName
{
get { return _RentalTypeName; }
set
{
_RentalTypeName = value;
NotifyPropertyChanged("RentalTypeName");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
The model class:
public class MasterRentalModel: INotifyPropertyChanged
{
private MasterRentalType _SelectedMasterRentalType;
private List<MasterRentalType> _MasterRentalTypeColl = new List<MasterRentalType>();
public MasterRentalType SelectedMasterRentalType
{
get { return _SelectedMasterRentalType; }
set
{
_SelectedMasterRentalType = value;
NotifyPropertyChanged("SelectedMasterRentalType");
}
}
public List<MasterRentalType> MasterRentalTypeColl
{
get { return _MasterRentalTypeColl; }
set { _MasterRentalTypeColl = value; }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
And in the code-behind, you just need to assign the model to the DataContext of you ComboBox; you can implement this any other function (here I have implemented it in the event handler of Loaded event of my Window):
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MasterRentalModel masterRentalModel = new MasterRentalModel();
// Fill the list of RentalType here
masterRentalModel.MasterRentalTypeColl.Add(new MasterRentalType() { RentalTypeId = "1", RentalTypeName = "Monthly" });
masterRentalModel.MasterRentalTypeColl.Add(new MasterRentalType() { RentalTypeId = "2", RentalTypeName = "Quarterly" });
masterRentalModel.MasterRentalTypeColl.Add(new MasterRentalType() { RentalTypeId = "1", RentalTypeName = "Yearly" });
cb_rentaltype.DataContext = masterRentalModel;
}
Whenever user changes the selection, SelectedMasterRentalType will be updated. And in the SelectedMasterRentalType, you can get both RentalTypeId and RentalTypeName. If you follow proper binding your model will always be updated; that's the essence of WPF.
Hope this will help.

WPF ListBox property binding not updating

I have the following setup:
XAML:
<ListBox x:Name="MyList" ItemsSource="{Binding MyItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Height="20" Width="20" Visibility="{Binding HasInformation, Converter={StaticResource VC}, ConverterParameter=True}" Source="/path/to/information.png" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" Padding="5,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note: The ConverterParameter being passed in simply controls whether the visibility is "Collapsed" (False), or "Hidden" (True), so in this case, I want the visibility to be Hidden.
ViewModel Snippet:
private ObservableCollection<IItem> _MyItems;
public ObservableCollection<IItem> MyItems
{
get
{
return _MyItems;
}
set
{
NotifyPropertyChanged(ref _MyItems, value, "MyItems");
}
}
private IItem _SelectedItem;
public IItem SelectedItem
{
get
{
return _SelectedItem;
}
set
{
NotifyPropertyChanged(ref _SelectedItem, value, "SelectedItem");
}
}
IItem:
public interface IItem
{
string Name { get; }
bool HasInformation { get; set; }
}
I populate an implementation of a list of IItem from a database into the list, and the information icon appears appropriately if HasInformation is true. This all works correctly.
However, if I set HasInformation by hand, the view does not update. I have tried:
In the ViewModel:
OnPropertyChanged("MyItems");
MyItems[MyItems.IndexOf(SelectedItem)].HasInformation = true;
// Note that "SelectedItem" is persisted correctly, and always
// points to the selected item that we want to update.
In the code behind:
MyList.GetBindingExpression(ItemsControl.ItemsSourceProperty).UpdateTarget();
All of these fire the getter of the MyItems property, but the view never updates and the icon never displays. I have ensured that the HasInformation property of the item that I updated does, in fact, remain true. I've attached to the PropertyChanged event to ensure that it's firing a property change for "MyItems" (it is, this also fires the getter), and I've even ensured that it's calling the value converter with the correct value for the HasInformation property (it is!), so what am I missing? Is there something weird with image showing/hiding or visibility value conversion that I'm not handling correctly?
ObservableCollection only notifies the collection changes not the changes in each of the item. In order to achieve your goal one of options is to change the IItem from interface to a class which implements INotifyPropertyChanged interface (or implement it in the IItem concrete type), and hook it with the ViewModel's PropertyChanged delegate (remember to unsubscribe it). See some of my code below.
ViewModel
public class MyViewModel: INotifyPropertyChanged
{
private ObservableCollection<Item> _MyItems;
public ObservableCollection<Item> MyItems
{
get
{
return _MyItems;
}
set
{
if (_MyItems != null)
{
foreach (var item in _MyItems)
{
item.PropertyChanged -= PropertyChanged;
}
}
if (value != null)
{
foreach (var item in value)
{
item.PropertyChanged += PropertyChanged;
}
}
OnPropertyChanged();
}
}
private Item _SelectedItem;
public Item SelectedItem
{
get
{
return _SelectedItem;
}
set
{
_SelectedItem = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Item
public class Item : INotifyPropertyChanged
{
private string _name;
private bool _hasInformation;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public bool HasInformation
{
get { return _hasInformation; }
set
{
_hasInformation = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}

ObservableCollection not updating View

I am just starting with MVVM and have hit a hurdle that I hope someone can help me with. I am trying to create a simple View with 2 listboxes. A selection from the first listbox will populate the second list box. I have a class created that stores the information I want to bind to.
MyObject Class (Observable Object is just a base class that implements INotifyPopertyChanged)
public class MyObject : ObservableObject
{
String _name = String.Empty;
ObservableCollection<MyObject> _subcategories;
public ObservableCollection<MyObject> SubCategories
{
get { return _subcategories; }
set
{
_subcategories = value;
RaisePropertyChanged("SubCategories");
}
}
public String Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
public MyObject()
{
_subcategories = new ObservableCollection<EMSMenuItem>();
}
}
In my viewmodel I have two ObservableCollections created
public ObservableCollection<EMSMenuItem> Level1MenuItems { get; set; }
public ObservableCollection<EMSMenuItem> Level2MenuItems { get; set; }
In my constructor of the ViewModel I have:
this.Level1MenuItems = new ObservableCollection<EMSMenuItem>();
this.Level2MenuItems = new ObservableCollection<EMSMenuItem>();
this.Level1MenuItems = LoadEMSMenuItems("Sample.Xml");
That works fine for the Level1 items and they correctly show in the View. However I have a command that gets called when the user clicks an item in the listbox, which has the following:
Level2MenuItems = ClickedItem.SubCategories;
For some reason this does not update the UI of the second listbox. If I put a breakpoint at this location I can see that Level2MenuItems has the correct information stored in it. If I write a foreach loop and add them individually to the Level2MenuItems collection then it does display correctly.
Also as a test I added the following to the constructor:
Level2MenuItems = Level1MenuItems[0].SubCategories;
And that updated correctly.
So why would the code work as expected in the constructor, or when looping through, but not when a user clicks on an item in the listbox?
You need to raise the change notification on the Level2MenuItems property.
Instead of having
public ObservableCollection<EMSMenuItem> Level2MenuItems { get; set; }
you need
private ObservableCollection<EMSMenuItem> _level2MenuItems;
public ObservableCollection<EMSMenuItem> Level2MenuItems
{
get { return _level2MenuItems; }
set
{
_level2MenuItems = value;
RaisePropertyChanged(nameof(Level2MenuItems));
}
}
The reason the former works in the constructor is that the Binding has not taken place yet. However since you are changing the reference via a command execute which happens after the binding you need to tell view that it changed
You need to make your poco class within the ObservableCollection implement INotifyPropertyChanged.
Example:
<viewModels:LocationsViewModel x:Key="viewModel" />
.
.
.
<ListView
DataContext="{StaticResource viewModel}"
ItemsSource="{Binding Locations}"
IsItemClickEnabled="True"
ItemClick="GroupSection_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="0,0,10,0" Style="{ThemeResource ListViewItemTextBlockStyle}" />
<TextBlock Text="{Binding Latitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{ThemeResource ListViewItemTextBlockStyle}" Margin="0,0,5,0"/>
<TextBlock Text="{Binding Longitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{ThemeResource ListViewItemTextBlockStyle}" Margin="5,0,0,0" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public class LocationViewModel : BaseViewModel
{
ObservableCollection<Location> _locations = new ObservableCollection<Location>();
public ObservableCollection<Location> Locations
{
get
{
return _locations;
}
set
{
if (_locations != value)
{
_locations = value;
OnNotifyPropertyChanged();
}
}
}
}
public class Location : BaseViewModel
{
int _locationId = 0;
public int LocationId
{
get
{
return _locationId;
}
set
{
if (_locationId != value)
{
_locationId = value;
OnNotifyPropertyChanged();
}
}
}
string _name = null;
public string Name
{
get
{
return _name;
}
set
{
if (_name != value)
{
_name = value;
OnNotifyPropertyChanged();
}
}
}
float _latitude = 0;
public float Latitude
{
get
{
return _latitude;
}
set
{
if (_latitude != value)
{
_latitude = value;
OnNotifyPropertyChanged();
}
}
}
float _longitude = 0;
public float Longitude
{
get
{
return _longitude;
}
set
{
if (_longitude != value)
{
_longitude = value;
OnNotifyPropertyChanged();
}
}
}
}
public class BaseViewModel : INotifyPropertyChanged
{
#region Events
public event PropertyChangedEventHandler PropertyChanged;
#endregion
protected void OnNotifyPropertyChanged([CallerMemberName] string memberName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(memberName));
}
}
}
Your Subcategories property should be read-only.

Categories

Resources