I have a panel and my idea is to have it populated by a stack panel containing two text boxes. When the user enters something in the left box, something should be generated in the right one, as follows.
<StackPanel Orientation="Horizontal">
<TextBox Name="Lefty" LostFocus="FillMyBuddy" />
<TextBox Name="Righty" LostFocus="FillMyBuddy" />
</StackPanel>
However, I'd like to add an option to add/remove rows and, since I wish not to limit myself to the number of such, I get a bit uncertain regarding the approach on two points.
Manipulating DOM (well, it's XAML/WPF but you see what I'm aiming at).
Event handling.
Is it a big no-no to programmatically affect the mark-up structure of the window? Or is it OK to add/remove panels during run-time?
What would the recommended way to be if I want the Lefty number 3 change stuff in Righty number 3? Anything more neat than checking the sender and pulling its siblings from the parent? I want to use a single event handler for any and all rows (knowing that the operations are always intra-row-wise).
You will want to follow MVVM, and have no code in your code-behind (programmatically affect the mark-up structure) files. The concept is easy when you grasp it, so learn it before you start writing your code.
In short, you are going to want to have a view model (something that implements INotifyPropertyChanged (INPC)) which holds your collection of items (which are going to be models, or view models in pure-MVVM). In "hybrid"-MVVM you could just have your models implement INPC.
Then, through the use of commands, you'd implement the logic to remove items from the list that its in. You can pass references, raise notification, using event bubbling, etc. (it's your preference) to have the item actually removed. In my case, I just passed a "manager" to the hybrid-model and held a reference to that. When the command is called (button is clicked), the model calls for the reference to remove itself from the list.
After you do that you define a DataTemplate to define what an "item" should look like one the View. You use a ItemsControl to show a collection of items, and bind to its ItemsSource so the collection of items are shown. Set your ItemsControl.ItemTemplate to the DataTemplate you created, and anything added to the collection bound to ItemsSource of the type defined in DataTemplate.DataType will render as you specify in the DataTemplate.
At the end of the day, you should learn about MVVM design, DataContext, INPC, Commands, Control types and their "main" properties, e.g. everything that inherits from ItemsControl has an ItemsSource property.
Here is a working example, where changing the original string, will reverse it and put it in the read-only right side text box:
MainWindow.xaml.cs (code-behind)
public partial class MainWindow : Window
{
StructureVm _struct = new StructureVm("Test");
public MainWindow()
{
InitializeComponent();
DataContext = _struct;
}
}
MainWindow.xaml (View)
<Window x:Class="DataTemplateWithCommands.MainWindow"
xmlns:local="clr-namespace:DataTemplateWithCommands"
Title="MainWindow" Height="350" Width="525" Background="Orange">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Model}"
x:Key="VmItem">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Original, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Encoded}"
IsReadOnly="True" />
<Button Content="X"
Command="{Binding RemoveMeCommand}" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource VmItem}">
</ItemsControl>
</Grid>
</Window>
Interface (helpful for Dependency Injection)
public interface IStructureManager
{
bool RemoveItem(Model itemToRemove);
}
ViewModel
public class StructureVm : IStructureManager
{
private readonly ObservableCollection<Model> _items;
private readonly string _title;
public StructureVm(string title)
{
_title = title;
_items = new ObservableCollection<Model>
{
new Model(this, "12"),
new Model(this, "23"),
new Model(this, "34"),
new Model(this, "45"),
new Model(this, "56"),
new Model(this, "67"),
new Model(this, "78"),
new Model(this, "89"),
};
}}
public ObservableCollection<Model> Items
{
get
{
return _items;
}
}
public string Title
{
get
{
return _title;
}
}
public bool RemoveItem(Model itemToRemove)
{
return _items.Remove(itemToRemove);
}
}
Model (not pure-MVVM, pure MVVM models don't implement INPC, and don't have Command in them)
public class Model : INotifyPropertyChanged
{
private readonly RelayCommand _removeMe;
private string _original;
private string _encoded;
private readonly IStructureManager _manager;
public string Original
{
get
{
return _original;
}
set
{
_original = value;
Encoded = ReverseString(_original);
NotifyPropertyChanged();
}
}
public string Encoded
{
get
{
return _encoded;
}
set
{
_encoded = value;
NotifyPropertyChanged();
}
}
public ICommand RemoveMeCommand
{
get
{
return _removeMe;
}
}
public Model(IStructureManager manager, string original)
{
Original = original;
_manager = manager;
_removeMe = new RelayCommand(param => RemoveMe(), param => CanRemoveMe);
}
private void RemoveMe()
{
_manager.RemoveItem(this);
}
private bool CanRemoveMe
{
get
{
//Logic to enable/disable button
return true;
}
}
private string ReverseString(string s)
{
char[] arr = s.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
RelayCommand implementation
From here on out all you have to do is change the attributes of your controls to whatever you're happy with and call it good. The example might be ugly, but I'm leaving it as an exercise for you to figure out other properties/attributes of WPF controls.
Related
I have a wpf application that I want to be able to launch a separate window in which I will have a listview bound to an observable collection. However I am unable to get the collection values to appear in the list view. Here is some of the code.
Window (Named WizardView):
(Data context defined like so at top of xaml):
d:DataContext="{d:DesignInstance Type=viewModels:MainViewModel}"
<Border Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" BorderBrush="Black">
<ListView BorderThickness="0" ItemsSource="{Binding TestModel.FailedTests}">
<Label Content="Introduction" FontWeight="Bold" />
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding }"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Border>
MainViewModel Code:
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
TestModel = new TestViewModel();
WizardModel = new WizardViewModel(TestModel);
}
private WizardViewModel _wizardModel;
public WizardViewModel WizardModel
{
get
{
return _wizardModel;
}
set
{
_wizardModel = value;
RaisePropertyChanged();
}
}
private TestViewModel _testViewModel;
public TestViewModel TestModel
{
get
{
return _testViewModel;
}
set
{
_testViewModel = value;
RaisePropertyChanged();
}
}
WizardViewModel Code:
public class WizardViewModel : TestViewModel
{
internal TestViewModel TestModel;
public WizardViewModel(TestViewModel testModel)
{
TestModel = testModel;
(TroubleShootCommand is defined in seperate UC, and launches fine)
TestModel.TroubleShootCommand = new DelegateCommand(Load, CanTroubleShoot);
}
public void Load()
{
(Sync Root is used because it is running on worker thread. Issue somewhere here?)
_syncRoot.Send(o =>
{
var troubleShootWizard = new WizardView();
troubleShootWizard.Owner = Application.Current.MainWindow;
troubleShootWizard.ShowDialog();
}, null);
}
Observable Collection in TestViewModel (Initialized in ctor):
private ObservableCollection<string> _failedTests;
public ObservableCollection<string> FailedTests
{
get { return _failedTests; }
set
{
_failedTests = value;
RaisePropertyChanged();
}
}
Any Help is appreciated, I feel like I have tried everything. I have watched values through the watch window under TestModel.FailedTests in the collection right before and right after launch.
First,
(Data context defined like so at top of xaml): d:DataContext="{d:DesignInstance Type=viewModels:MainViewModel}"
This is a mistake, this way d: you are defining the DataContext at design time..
You can create the viewmodel inside .xaml this way:
<WizardView.DataContext>
<viewModels:MainViewModel/>
</WizardView.DataContext>
Using the design time declaration can help in many ways like knowing the viewmodel in case you are creating it and assigning it in C# (or via a IoC mechanism), also it helps tools like IntelliSense and ReSharper to analyze your bindings and warn you if you misspell a property's name in xaml, auto-completion, etc... (more on this can be found here, and here)
Second, if you are assigning the WizardViewModel in your .xaml the same way (i.e. design-time), then you can either do it in your Load() function (add troubleShootWizard.DataContext = this;) or assign it in .xaml the same way I've mentioned before.
I'm having trouble setting up an automatic binding.
I have a simple WPF application with two classes - MovieInfo (contains information about movie files on my filesystem) and a MediaScanner class that just returns a List<MovieInfo>. In my MainWindow.xaml, I have a ListBox:
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="242" Margin="10,35,0,0" VerticalAlignment="Top" Width="237" d:ItemsSource="{Binding MovieList}"/>
Also in the XAML added to the <Window ...> is
Name="MainWindow1"
DataContext="{Binding ElementName=MainWindow1}"
In the code behind, I made a public property of the MainWindow : Window:
public ObservableCollection<MovieInfo> MovieList { get; set; }
In the constructor:
public MainWindow()
{
DataContext = this;
MovieList = new ObservableCollection<MovieInfo>();
InitializeComponent();
//this doesn't do anything for me
//listBox.ItemsSource = MovieList;
}
I have a button that calls:
private void button_Click(object sender, RoutedEventArgs e)
{
var scanner = new MediaScanner();
MovieList = new ObservableCollection<MovieInfo>(scanner.ScanAll().OrderBy(x => x.Title));
//listBox.ItemsSource = MovieList;
}
It's my understanding that this should take care of everything, yet the ListBox won't populate unless I uncomment the listBox.ItemsSource = MovieList; where it is in the button_Click.
What am I missing?
The ListBox does not bind the MovieList at runtime because you prefixed ItemsSource with d.
After adding the namespaces, you can put d: in front of any attribute or control to show it only in the XAML Designer but not at runtime. [...]
You can use d: with attributes for any UWP or WPF .NET Core control, like colors, font sizes, and spacing. You can even add it to the control itself.
These namespaces are defined on your XAML root element.
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
In order to make the binding work at runtime, remove the d: or add another ItemsSource without the d: prefix so that you have different sources for design and runtime.
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="242" Margin="10,35,0,0" VerticalAlignment="Top" Width="237" ItemsSource="{Binding MovieList}"/>
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="242" Margin="10,35,0,0" VerticalAlignment="Top" Width="237" d:ItemsSource="{Binding DesignTimeMovieList}" ItemsSource="{Binding MovieList}"/>
Another issue is that you neither implement a dependency property for your movie list collection nor INotifyPropertyChanged. In practice this means although you assign a new collection to the MovieList property in your button click event handler, the binding does not get notified of the change and will still use the old collection instance. Of course listBox.ItemsSource = MovieList; would work here, but it assigns the collection directly and overwrites the binding, so this is a different solution.
In the long run, you should probably apply the MVVM pattern and separate the data to be bound in a view model that implements INotifyPropertyChanged, which solves your issue and at the same time separates your view and your logic and data that are then connected via bindings.
Example of a dependency property for your window.
public partial class MainWindow : Window
{
public ObservableCollection<MovieInfo> MovieList
{
get => (ObservableCollection<MovieInfo>)GetValue(MovieListProperty);
set => SetValue(MovieListProperty, value);
}
public static readonly DependencyProperty MovieListProperty = DependencyProperty.Register(
nameof(MovieList), typeof(ObservableCollection<MovieInfo>), typeof(MainWindow), new PropertyMetadata(null));
public MainWindow()
{
DataContext = this;
MovieList = new ObservableCollection<MovieInfo>();
InitializeComponent();
// ...other code.
}
private void button_Click(object sender, RoutedEventArgs e)
{
var scanner = new MediaScanner();
MovieList = new ObservableCollection<MovieInfo>(scanner.ScanAll().OrderBy(x => x.Title));
}
// ...other code.
}
Example for a view model in case you want to move to MVVM.
public class MyViewModel : INotifyPropertyChanged
{
private ObservableCollection<MovieInfo> _movieList;
public ObservableCollection<MovieInfo> MovieList
{
get => _movieList;
set
{
if (_movieList == value)
return;
_movieList = value;
OnPropertyChanged();
}
}
// ...other code.
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
As a final remark, you should consider reusing the ObservableCollection<MovieInfo> MovieList instead of creating and assigning a new one each time. This type of collection provides change notifications for adding, removing and replacing items, which will automatically be reflected in the user interface. Exposing an observable collection, but instead of modifying, replacing it, is pointless. If a collection is always replaced, a simple List<T> will do the same.
Summary
I've got an element within a data template, that I want bound to some property of the main data context.
I realise that in this specific situation, a different solution may be preferable (and I have a working solution that avoids this), but I suspect this kind of problem may come up again and I want to know how to solve it in the general case.
Below are the specifics of my situation.
The Details
Data Hierarchy: I have a list of type A, each instance of A has a list of type B, each instance of B has some other data including a string for a text log.
UI Structure: I have a ComboBox to select an item of type A. I have a TabControl with the tabs representing items of type B, taken from the selected A above. In each tab, there is a means to enter data to populate the object of type B, and a log, representing changes to that instance of B.
Backing Logic: I track the selected item in each list with properties (SelectionA and SelectionB in the data context, MainWindowViewModel) that notify when they change. The B object also notifies when its log text changes. These ensure that the UI responds to changes to the backing data.
Problem: I want to move the notify logic to all be in one place (the DataContext, i.e. MainWindowViewModel), rather than having some in the B class and needing to duplicate the notify logic. To achieve this, I add a property (SelectionBLogText) to track the LogText property of the SelectionB object, and bind the log (in the templated tabpanel) to the main SelectionBLogText property. The problem is that within the tabpage, I can only seem to bind to properties of the selected B object (from the selected tab), and I need to bind to a property of the DataContext instead. I've tried using RelativeSource but nothing I've tried so far works, and the more I look at the docs the more I feel it's designed for another job.
The XAML (with irrelevant details removed):
<Window x:Class="WPFQuestion.MainWindow"
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:WPFQuestion"
mc:Ignorable="d"
Title="MainWindow"
Height="350"
Width="930">
<DockPanel>
<ComboBox
ItemsSource="{Binding ListOfA}"
SelectedItem="{Binding SelectionA}"
DisplayMemberPath="Name"/>
<TabControl
ItemsSource="{Binding SelectionA}"
SelectedItem="{Binding SelectionB}"
DisplayMemberPath="Name">
<TabControl.ContentTemplate>
<ItemContainerTemplate>
<StackPanel>
<TextBox
IsReadOnly="True"
Text="{Binding Path=???.SelectionBLogText}"/>
<Button Click="ClearLogButton_Click"/>
</StackPanel>
</ItemContainerTemplate>
</TabControl.ContentTemplate>
</TabControl>
</DockPanel>
</Window>
And the code-behind:
public partial class MainWindow : Window
{
internal MainWindowViewModel vm;
public MainWindow()
{
InitializeComponent();
vm = new MainWindowViewModel();
DataContext = vm;
}
// Various methods for event handling
}
public class A : IEnumerable<B>
{
public string Name { get; set; }
public List<B> Bs { get; set; }
}
public class B // previously : INotifyPropertyChanged
{
public string Name { get; set; }
public string LogText { get; set; }
// various other properties
}
public class MainWindowViewModel : INotifyPropertyChanged
{
private A _a;
private B _b;
public event PropertyChangedEventHandler PropertyChanged;
public List<A> ListOfA { get; set; }
public A SelectionA
{
get => _a;
set
{
if (_a == value)
{
return;
}
_a = value;
RaisePropertyChanged(nameof(SelectionA));
}
}
public B SelectionB
{
get => _b;
set
{
if (_b == value)
{
return;
}
_b = value;
RaisePropertyChanged(nameof(SelectionB));
RaisePropertyChanged(nameof(SelectionBLogText));
}
}
public string SelectionBLogText
{
get => SelectionB.LogText;
set
{
if (SelectionB.LogText == value)
{
return;
}
SelectionB.LogText = value;
RaisePropertyChanged(nameof(SelectionBLogText));
}
}
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
have you tried something like this when you used relative binding? if not please check this out.
<TextBox IsReadOnly="True"
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window},
Path=Datacontext.SelectionBLogText}"/>
I am new in the WPF.
I want to make the list of buttons from a list of a class say "Buttons" and having two fields (ButtonContent,ButtonID) in the MainForm in WPF.
The idea behind this is that when the MainForm will be loaded then i want to make buttons list dynamically.
The Best Example is already given in the Link
http://www.codeproject.com/Articles/25030/Animating-Interactive-D-Elements-in-a-D-Panel
But i only want to make the equal size buttons stacked horizontally.
How can i do this in WPF? Thank you in advance.
This is the way I would do it. There are some areas here that will need further research on your part, but this will get you started.
First you need your ViewModel. This is the plain old object. It exposes the properties and methods that are pertinent to your business. You mentioned ButtonContent and ButtonID. Let's assume that both of those are strings for now. You'll also need a command for your button I assume.
public class ButtonViewModel : INotifyPropertyChanged
{
private string _content;
public string Content
{
get{ return _content; }
set{ _content = value; OnPropertyChanged("Content"); }
}
// you'll need to implement INotifyPropertyChanged
// also take a look at RelayCommand
// here is your command for you're button
public ICommand ButtonCommand
{
get { return new RelayCommand(execute, canExecute); }
}
private void execute()
{
// my actual command code
}
private bool canExecute()
{
// this will automatically toggle the enabled state on my button
}
}
You'll have one more view model. This will be the DataContext of your MainWindow.
public class AppViewModel
{
public ObservableCollection<ButtonViewModel> MyButtons {get; set; }
public AppViewModel()
{
MyButtons = new ObservableCollection<ButtonViewModel>();
// add some demo data
MyButtons.Add(new ButtonViewModel() {ButtonContent = "Click Me!"});
}
}
Now you need to implement the view. In the MainWindow xaml code. Add your xmlns:local namespace.
<Window.DataContext>
<local:AppViewModel />
</Window.DataContext>
<ListBox ItemsSource="{Binding MyButtons}">
<ListBox.ItemsTemplate>
<DataTemplate>
<Button Command="{Binding ButtonCommand}" Content="{Binding Content}"/>
</DataTemplate>
<ListBox.ItemsTemplate>
</ListBox>
Hopefully this can get you started in the right direction.
I am developing windows phone app .In app,I want to put multiple check box.I able to put multiple check box.But when i checked on check box i want getting its content(check box content).For that i am use checked event and also click event but i cant get result as i want.My xaml code is as below:
<ListBox Name="hobbylist" ItemsSource="{Binding}" Margin="0,0,10,10" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="hobbycheck" Content="{Binding Path=Title}"
IsChecked="{Binding IsSelected}" ClickMode="Release"
Click="CheckBox_Click" ></CheckBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Please help me ...
I think you are using the Checkbox not correctly according to its purpose.
Checkbox should represent a state (e.g. yes/no) regarding a subject. Still, you just have to use the Checked event when the checkbox gets checked and Unchecked otherwise.
So in the Checked event, get the content you wish.
Edit
You have to maintain this with the MVVM pattern somehow. For that, there are plenty of examples in the internet, I am sure you can handle that.
Instead of having Click="CheckBox_Click", use the Check event :
private void CheckBox_Checked (Object sender, EventArgs e)
{
var currentCheckBoxItem = sender as CheckBox;
if (currentCheckBoxItem.IsChecked == true)
{
//you manipulation here...
}
}
Still. this might just not work, because you haven't provided enough details of your matter.
Edit 2 A little of MVVM...
First, make a Hobby model class, with a single string property (you might change your mind later to add more properties, Idk) :
public class Hobby : INotifyPropertyChanged
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
OnPropertyChanged();
}
}
private bool _isSelected;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
OnPropertyChanged();
}
}
//You can add some multiple properties here (***)
public Hobby (string hobbyName, bool isSelected)
{
Name = hobbyName;
IsSelected = isSelected;
}
//INotifiyPropertyChanged interface member implementation ...
}
(* ) For example, a short description and then bind it on the View. The major advantage of this MVVM pattern is logic separation, so if something has to change, the separation of each component makes it easier.
Second, create a ViewModel class (you should implement INotifyPropertyChanged interface) :
public class HobbiesViewModel : INotifyPropertyChanged
{
private ObservableCollection<Hobby> _hobbies;
public ObservableCollection<Hobby> HobbiesCollection
{
get
{
return _hobbies;
}
set
{
_hobbies = value;
OnPropertyChanged();
}
}
//Constructor
public HobbiesViewModel
{
HobbiesCollection = new ObservableCollection<Hobby>();
}
//INotifyPropertyChanged interface member implementation ...
}
Third, create an instance of the ViewModel (the ObservableCollection). Use this quick help out : In the App.xaml.cs, create a static object and use it through the app as you need it :
public partial class App
{
//This already exists in your app's code, but I've written it to
//make an idea where to write the Hobbies object
public static PhoneApplicationFrame RootFrame { get; private set; }
public static HobbiesViewModel Hobbies;
//Again, the already existing constructor
public App()
{
...
Hobbies = new HobbiesViewModel();
}
Now, you almost have it all set; You have the Model, you have the ViewModel, all that's left is to create the connection with the View. This can be easily done through binding. The ViewModel represents the DataContext of your control (in your case the LongListSelector, so in that View's (Page's) constructor, write the following statement :
yourListControlName.DataContext = App.Hobbies;
Now the binding is the only thing left. This is done in XAML code. I won't put a whole chunk of XAML code here, cause you know best how your control looks like. Still, judging by the short sample you provided, there a few adjustments only :
The items source of the list XAML control will be bound to the ObservableCollection object name of the ViewModel representing the control's DataContext. A bit fuzzy, huh? To be clearer, in this case, you need to write ItemsSource="{Binding HobbiesCollection}", the ObservableCollection. Also, in the template, you should have that CheckBox which is bound on your Model's properties :
<DataTemplate>
<StackPanel Orientation="Horizontal"> //StackPanel is kinda useless if you have
//only one child control in it. But I wrote
//according to your code.
<Checkbox Content="{Binding Name}" IsChecked="{Binding IsSelected, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
Now, here things are a bit unclear to me. Why would you use the Checkbox? I've thought of the next possible scenario : You come with some string of your hobbies through deserialization of the Json Data. To add them to the ViewModel, you need only :
App.Hobbies.HobbiesCollection.Add(new Hobby("firstHobbyFromJson", true));
App.Hobbies.HobbiesCollection.Add(new Hobby("secondHobbyFromJson", true));
This would make all hobbies already selected in the View. I guess, you would add some other hobbies, the user doesn't have which are not selected and could add them now :
App.Hobbies.HobbiesCollection.Add(new Hobby("aNewHobby", false));
App.Hobbies.HobbiesCollection.Add(new Hobby("anotherNewHobby", false));
At this point, the user has all its previous hobbies in the list and as well some new hobbies you provided him. After his selection is done, if you need to serialize the Json with only the selected hobbies, you could get like this :
var userHobbies = App.Hobbies.HobbiesCollection.Where(h => h.IsSelected);
or with a foreach and get only those hobby objects which have the IsSelected property as true.
Good luck!
I found a Simpler solution.
My Model
You need to use two variables otherwise you may get an 'stackoverflowexception'
public class ModelObj
{
public int position { set; get; }
public bool isChecked
{
get { return IsChecked; }
set { IsChecked = value; }
}
public bool IsChecked;
}
Code to be added in xaml:
isChecked in xaml sets the ListView Checkbox
Mode=TwoWay updates the isChecked boolean value of the model class
<CheckBox IsChecked="{Binding isChecked , Mode=TwoWay}" Checked="checkBox_Checked" >
c# Code that handles the event
private void checkBox_Checked(object sender, RoutedEventArgs e)
{
foreach (ModelObj obj in listItem)
{
if (obj.isChecked == true)
{
int selectedPosition = obj.position;
}
}
}