How would I be able to change the data in my ObservableCollection without adding or using add to my collection?
var items = await service.GetTrucksAsync();
foreach (var item in items)
{
MyCollection.Add(new TruckItems
{
TruckId = item.TruckId,
TruckQuoteId = item.QuoteId,
TruckPhaseId = item.CurrentPhaseId,
TruckChassisManufacturer = item.ChassisManufacturer,
TruckChassisModel = item.ChassisModel,
TruckStatus = item.Status,
TruckJobNumber = item.JobNumbers,
TruckAddedBy = item.AddedBy,
TruckClientName = item.ClientName,
TruckClientSurname = item.ClientSurname,
TruckClientDetail = item.ClientDetail,
TruckCurrentPhase = item.CurrentPhase
});
}
dgViewProjects.ItemsSource = MyCollection;
I do not want to clear the collection and the add data again, as it causes my datagrid's UI to 'flicker' (clear and load new data again). I need it to be smooth as hell. :)
EDIT: INotifyPropertyChanged is implemented in my class
public class TruckItems : INotifyPropertyChanged
{
...
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
You TruckItems class needs to implement the INotifyPropertyChanged interface.
For example:
public class TruckItems : INotifyPropertyChanged
{
private int _truckQuoteId;
public int TruckQuoteId
{
get { return _truckQuoteId; }
set
{
if(value != _truckQuoteId)
{
value = _truckQuoteId;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TruckQuoteId));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
If you're unable to alter the TruckItems class (DAL), you need to create a new class and copy the properties. (for example using a Mapper)
update:
The problem you are facing is, that you're creating a new instance of TruckItems.
var items = await service.GetTrucksAsync();
foreach (var item in items)
{
var truckItem = MyCollection.FirstOrDefault(i => i.TruckId == item.TruckId);
bool isNew = false;
if(truckItem == null)
{
truckItem = new TruckItems();
isNew = true;
}
truckItem.TruckId = item.TruckId;
truckItem.TruckQuoteId = item.QuoteId;
truckItem.TruckPhaseId = item.CurrentPhaseId;
truckItem.TruckChassisManufacturer = item.ChassisManufacturer;
truckItem.TruckChassisModel = item.ChassisModel;
truckItem.TruckStatus = item.Status;
truckItem.TruckJobNumber = item.JobNumbers;
truckItem.TruckAddedBy = item.AddedBy;
truckItem.TruckClientName = item.ClientName;
truckItem.TruckClientSurname = item.ClientSurname;
truckItem.TruckClientDetail = item.ClientDetail;
truckItem.TruckCurrentPhase = item.CurrentPhase;
if(isNew )
MyCollection.Add(truckItem);
}
Related
I had some problems with serialization of my classes implementing INotifyPropertyChanged events. (Binary Serialization of ViewModel (ObservableCollection))
Solved as recommended in SerializationException when serializing instance of a class which implements INotifyPropertyChanged
Now I have a problem with the deserialization. When doing it like
BinaryFormatter formatter = new BinaryFormatter();
FileStream fs_open = new FileStream(#"C:\Users\vm_user\Documents\Visual Studio 2015\testbin.txt", FileMode.Open);
ViewModels.MainViewModel mvm1 = (ViewModels.MainViewModel)formatter.Deserialize(fs_open);
fs_open.Close();
The deserialized objects do not fire any events anymore.
What do I have to do to get the same functionality as before the serialization? Right now I do it with this:
BinaryFormatter formatter = new BinaryFormatter();
ViewModels.MainViewModel mvm1 = new ViewModels.MainViewModel();
FileStream fs_open = new FileStream(#"C:\Users\vm_user\Documents\Visual Studio 2015\testbin.txt", FileMode.Open);
foreach (ViewModels.WatchedFile file in ( (ViewModels.MainViewModel)formatter.Deserialize(fs_open) ).WatchedFiles)
{
ViewModels.WatchedFile wf = new ViewModels.WatchedFile(file.Name, file.Path, file.Tags, new ObservableCollection<ViewModels.WatchedFile>());
foreach (ViewModels.WatchedFile subs in file.Subs)
{
wf.Subs.Add(refeshLoadedFiles(subs));
}
mvm1.WatchedFiles.Add(wf);
}
fs_open.Close();
and refreshLoadedFiles:
private ViewModels.WatchedFile refeshLoadedFiles( ViewModels.WatchedFile fileSource)
{
ViewModels.WatchedFile wf = new ViewModels.WatchedFile(fileSource.Name, fileSource.Path, fileSource.Tags, new ObservableCollection<ViewModels.WatchedFile>());
foreach (ViewModels.WatchedFile subs in fileSource.Subs)
{
wf.Subs.Add(refeshLoadedFiles(subs));
}
return wf;
}
But this canĀ“t be the goal of serialization, can it? Beacause if I do it this way I can write my information into any textfile with simple text stating the type and then all the rest...
Thanks for your help.
This is the ViewModel (edit):
namespace WatchedFile.ViewModels
{
[Serializable()]
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
[Serializable()]
public class WatchedFile : ViewModelBase
{
#region Name Property
private String _name = default(String);
public String Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
OnPropertyChanged();
}
}
}
#endregion Name Property
#region Path Property
private String _path = default(String);
public String Path
{
get { return _path; }
set
{
setDisplayImage(value);
if (value != _path)
{
_path = value;
OnPropertyChanged();
}
}
}
#endregion Path Property
#region Tags Property
private ObservableCollection<Tag> _tags = new ObservableCollection<Tag>();
public ObservableCollection<Tag> Tags
{
get { return _tags; }
protected set
{
if (value != _tags)
{
_tags = value;
OnPropertyChanged();
}
}
}
#endregion Tags Property
#region Subs Property
private ObservableCollection<WatchedFile> _subs = new ObservableCollection<WatchedFile>();
public ObservableCollection<WatchedFile> Subs
{
get { return _subs; }
protected set
{
setDisplayImage(Path);
if (value != _subs)
{
_subs = value;
_subs.CollectionChanged += _subs_CollectionChanged;
OnPropertyChanged();
}
}
}
private void _subs_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
Subs = Sort(Subs);
}
#endregion Subs Property
[NonSerialized()]
private BitmapImage _displayImage = default(BitmapImage);
public BitmapImage DisplayImage
{
get { return _displayImage; }
protected set
{
if (value != _displayImage)
{
_displayImage = value;
OnPropertyChanged();
}
}
}
public WatchedFile(): this(string.Empty,string.Empty,new ObservableCollection<Tag>(),new ObservableCollection<WatchedFile>())
{
}
public WatchedFile(String name, String path, ObservableCollection<Tag> tags, ObservableCollection<WatchedFile> subitems)
{
Subs = WatchedFile.Sort(subitems);
Name = name;
Path = path;
Tags = tags;
}
public static ObservableCollection<WatchedFile> Sort(ObservableCollection<WatchedFile> files)
{
if (files == null)
return files;
ObservableCollection<WatchedFile> filesReturn = new ObservableCollection<ViewModels.WatchedFile>();
WatchedFile[] sortedArray = files.ToArray();
WatchedFile temp;
for (int j = 1; j <= sortedArray.Length - 1; j++)
{
for (int i = j; i > 0; i--)
{
if (sortedArray[i].Subs != null && sortedArray[i].Subs.Count > 1)
{
ObservableCollection<WatchedFile> subs = Sort(sortedArray[i].Subs);
sortedArray[i].Subs.Clear();
foreach (WatchedFile f in subs)
sortedArray[i].Subs.Add(f);
}
if (sortedArray[i - 1].Subs != null && sortedArray[i - 1].Subs.Count > 1)
{
ObservableCollection<WatchedFile> subs = Sort(sortedArray[i - 1].Subs);
sortedArray[i - 1].Subs.Clear();
foreach (WatchedFile f in subs)
sortedArray[i - 1].Subs.Add(f);
}
if (( sortedArray[i].Name ).CompareTo(sortedArray[i - 1].Name) == -1)
{
temp = sortedArray[i];
sortedArray[i] = sortedArray[i - 1];
sortedArray[i - 1] = temp;
}
else
break;
}
}
filesReturn.Clear();
foreach (WatchedFile f in sortedArray)
filesReturn.Add(f);
return filesReturn;
}
}
[Serializable()]
public class Tag
{
public Tag(String value)
{
Value = value;
}
public String Value { get; private set; }
}
[Serializable()]
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
}
#region WatchedFiles Property
private ObservableCollection<WatchedFile> _watchedFiles = new ObservableCollection<WatchedFile>();
public ObservableCollection<WatchedFile> WatchedFiles
{
get { return _watchedFiles; }
protected set
{
if (value != _watchedFiles)
{
_watchedFiles =WatchedFile.Sort(value);// value;
_watchedFiles.CollectionChanged += _watchedFiles_CollectionChanged;
OnPropertyChanged();
}
}
}
private void _watchedFiles_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
WatchedFiles = WatchedFile.Sort(WatchedFiles);
}
#endregion WatchedFiles Property
}
}
They don't fire because nothing is subscribed to them. In WPF, the framework will subscribe during binding in the background when the view or control is loaded. Since you're doing this at a different stage in the pipeline, you're going to have to figure out a better way to load the model at the right stage so that the subscriptions occur again. Hard to say without seeing more, but this is very smelly. Is this a control or the full view's datacontext?
At the very least, force a rebind of the model. Otherwise, maybe serialize a dto instead and inject into the viewmodel and use it to restore state before loading the view, or give the main view model a method that takes the dto and rebinds it to an observable property. Like I said, it's hard to say without seeing what you're really doing.
I am trying to create a SwitchCell with a list of Elements.
Eventhough I found out how to do that with a plain string-List thanks to stackoverflow I can't find out what I'm doing wrong when I try to bind the Cell-Properties to a self-made struct.
This is my code:
public class RestaurantFilter
{
public List<FilterElement> Types;
public RestaurantFilter(List<string> types)
{
Types = new List<FilterElement>();
foreach (string type in types)
Types.Add(new FilterElement { Name = type, Enabled = false });
}
}
public struct FilterElement
{
public string Name;
public bool Enabled;
}
public FilterPage()
{
List<string> l = new List<string>(new string[] { "greek", "italian", "bavarian" });
RestaurantFilter filter = new RestaurantFilter(l);
ListView types = new ListView();
types.ItemTemplate = new DataTemplate(() =>
{
var cell = new SwitchCell();
cell.SetBinding(SwitchCell.TextProperty, "Name");
cell.SetBinding(SwitchCell.IsEnabledProperty, "Enabled");
return cell;
});
types.ItemsSource = filter.Types;
Content = types;
}
But the SwitchCell's in the Application do not show the Name or the Boolean.
About the IsEnabledProperty - there seem to be a knonw bug with the IsEnabled property that will be fixed in the Xamarin.Forms 2.3.0-pre1 release so that might be related to your case:
https://bugzilla.xamarin.com/show_bug.cgi?id=25662
About the Name property - try changing your FilterElement struct to a class with properties and PropertyChangedEventHandler like this and it will work:
public class FilterElement
{
public event PropertyChangedEventHandler PropertyChanged;
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
private bool _enabled;
public bool Enabled
{
get { return _enabled; }
set
{
_enabled = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Enabled"));
}
}
}
}
That way you will be able to update the Types list and it will automatically update the ListView.
By the way, if you want to turn the filter on or off based on your ViewModels (not enable or disable it), you need to use the OnProperty for the binding:
https://developer.xamarin.com/api/field/Xamarin.Forms.SwitchCell.OnProperty/
I am creating varied number of MvxSpinners programmatically. The number of the MvxSpinners generated cannot be predetermined. It is determined by the user input.
I have a List<Beneficiary>. Each MvxSpinner is meant to update each Beneficiary in the collection.
Since I cannot determine the number of MvxSpinner (which corresponds to the count of the Beneficiary in the collection) to be generated, I am forced to have one ICommand to handle all the HandleSelectedItem event of the MvxSpinners.
The Challenge
I am having difficulty determining the index of the List<Beneficiary> to update depending on the MvxSpinner the user clicked.
An Example
let
var BeneficiaryList=new List<Beneficiary>()
If there are 5 Beneficiary object in the collection, 5 MvxSpinner will be generated.
If the user selects a MVXSpinner which is meant to update index 2 of the collection, how do i determine the index of Beneficary to update?
What I have tried
private IList<Beneficiary> _beneficiaryList;
public IList<Beneficiary> BeneficiaryList
{
get { return _beneficiaryList; }
set { _beneficiaryList= value; RaisePropertyChanged(() => BeneficiaryList); }
}
public ICommand UpdateBeneficiary=> new MvxCommand<Beneficiary>(item =>
{
//item is of type Beneficiary
//But I do not know which index of BeneficiaryList to update
});
Your help will be deeply appreciated.
You probably need a List of ICommands too, one for each spinner. Something like this in your view model...
private IList<ICommand> _commands;
public IList<ICommand> Commands {
get {
if (_commands == null) {
_commands = BeneficiaryList.Select(x => new MvxCommand<Beneficiary>(item => {
...
}));
}
return _commands;
}
}
And set up your bindings like this (assuming you've got a list of spinners)
for (int i = 0; i < spinners.Count; i++) {
var spinner = spinners[i];
set.Bind (spinner).To(vm => vm.Commands[i]);
}
Well, it is interesting to answer my own question.
What I did was to give each Spinner a unique ID that corresponds to the index of the collection.
I created a custom Spinner called MvxSpinnerIndexer extending MvxSpinner (I really do not think it matters. You can just extend Spinner). MvxSpinnerIndexer retrieved the Id and the SelectedItem and then placed the two into a Dictionary
Here is the source for MvxSpinnerIndexer
public class MvxSpinnerIndexer : Spinner
{
public MvxSpinnerIndexer(Context context, IAttributeSet attrs)
: this(
context, attrs,
new MvxAdapter(context)
{
SimpleViewLayoutId = global::Android.Resource.Layout.SimpleDropDownItem1Line
})
{ }
public MvxSpinnerIndexer(Context context, IAttributeSet attrs, IMvxAdapter adapter)
: base(context, attrs)
{
var itemTemplateId = MvxAttributeHelpers.ReadListItemTemplateId(context, attrs);
var dropDownItemTemplateId = MvxAttributeHelpers.ReadDropDownListItemTemplateId(context, attrs);
adapter.ItemTemplateId = itemTemplateId;
adapter.DropDownItemTemplateId = dropDownItemTemplateId;
Adapter = adapter;
SetupHandleItemSelected();
}
public new IMvxAdapter Adapter
{
get { return base.Adapter as IMvxAdapter; }
set
{
var existing = Adapter;
if (existing == value)
return;
if (existing != null && value != null)
{
value.ItemsSource = existing.ItemsSource;
value.ItemTemplateId = existing.ItemTemplateId;
}
base.Adapter = value;
}
}
[MvxSetToNullAfterBinding]
public IEnumerable ItemsSource
{
get { return Adapter.ItemsSource; }
set { Adapter.ItemsSource = value; }
}
public int ItemTemplateId
{
get { return Adapter.ItemTemplateId; }
set { Adapter.ItemTemplateId = value; }
}
public int DropDownItemTemplateId
{
get { return Adapter.DropDownItemTemplateId; }
set { Adapter.DropDownItemTemplateId = value; }
}
public ICommand HandleItemSelected { get; set; }
public int ViewId { get; set; }
private void SetupHandleItemSelected()
{
ItemSelected += (sender, args) =>
{
//sender.
var control = (MvxSpinnerIndexer)sender;
var controlId = control.Id;
var position = args.Position;
HandleSelected(position, controlId);
};
}
protected virtual void HandleSelected(int position, int? controlId)
{
var item = Adapter.GetRawItem(position);
var content = new Dictionary<string, object> {{"Index", controlId}, {"SelectedItem", item}};
//var param = new ListItemWithIndexModel { Index = controlId, SelectedItem = item };
if (HandleItemSelected == null
|| item == null
|| !HandleItemSelected.CanExecute(content))
return;
HandleItemSelected.Execute(content);
}
}
In your ViewModel
public ICommand SpinnerSelected => new MvxCommand<Dictionary<string, object>>(item =>
{
var selectedItem = item["SelectedItem"] as ListItemModel;//Cast to the actual model
var index = item["Index"] as int?;//The index of the collection to update
});
I believe this will be useful to the community.
Say I have a BindingList<Person> where Person has a public string property called Name. Is there a way to effectively (if not directly) bind to the Current property (which is a Person object) and then index into the Name property?
I'm imagining a binding set up like
nameLabel.DataBindings.Add(
new Binding("Text", this.myBindingListSource, "Current.Name", true));
or
nameLabel.DataBindings.Add(
new Binding("Text", this.myBindingListSource.Current, "Name", true));
Both of these approaches produce runtime errors.
Currently, I am simply subscribing to the BindingList's CurrentChanged event and handling updates in there. This works but I would prefer the DataBinding approach if possible.
Using the NestedBindingProxy class provided below, you can do
nameLabel.DataBindings.Add(
new Binding("Text", new NestedBindingProxy(this.myBindingListSource, "Current.Name"), true));
Below is the c# code for NestedBindingProxy. The problem with WinForms data binding is it doesn't detect value changes when you use a navigation path that contains multiple properties. WPF does this though. So I created the class NestedBindingProxy that does the change detection and it exposes a property called "Value" that the windows binding can bind too. Whenever any property changes in the navigation path, the notify property changed event will fire for the "Value" property.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
namespace WindowsFormsApplication4
{
public sealed class NestedBindingProxy : INotifyPropertyChanged
{
class PropertyChangeListener
{
private readonly PropertyDescriptor _prop;
private readonly WeakReference _prevOb = new WeakReference(null);
public event EventHandler ValueChanged;
public PropertyChangeListener(PropertyDescriptor property)
{
_prop = property;
}
public object GetValue(object obj)
{
return _prop.GetValue(obj);
}
public void SubscribeToValueChange(object obj)
{
if (_prop.SupportsChangeEvents)
{
_prop.AddValueChanged(obj, ValueChanged);
_prevOb.Target = obj;
}
}
public void UnsubsctribeToValueChange()
{
var prevObj = _prevOb.Target;
if (prevObj != null)
{
_prop.RemoveValueChanged(prevObj, ValueChanged);
_prevOb.Target = null;
}
}
}
private readonly object _source;
private PropertyChangedEventHandler _subscribers;
private readonly List<PropertyChangeListener> _properties = new List<PropertyChangeListener>();
private readonly SynchronizationContext _synchContext;
public event PropertyChangedEventHandler PropertyChanged
{
add
{
bool hadSubscribers = _subscribers != null;
_subscribers += value;
bool hasSubscribers = _subscribers != null;
if (!hadSubscribers && hasSubscribers)
{
ListenToPropertyChanges(true);
}
}
remove
{
bool hadSubscribers = _subscribers != null;
_subscribers -= value;
bool hasSubscribers = _subscribers != null;
if (hadSubscribers && !hasSubscribers)
{
ListenToPropertyChanges(false);
}
}
}
public NestedBindingProxy(object source, string nestedPropertyPath)
{
_synchContext = SynchronizationContext.Current;
_source = source;
var propNames = nestedPropertyPath.Split('.');
Type type = source.GetType();
foreach (var propName in propNames)
{
var prop = TypeDescriptor.GetProperties(type)[propName];
var propChangeListener = new PropertyChangeListener(prop);
_properties.Add(propChangeListener);
propChangeListener.ValueChanged += (sender, e) => OnNestedPropertyChanged(propChangeListener);
type = prop.PropertyType;
}
}
public object Value
{
get
{
object value = _source;
foreach (var prop in _properties)
{
value = prop.GetValue(value);
if (value == null)
{
return null;
}
}
return value;
}
}
private void ListenToPropertyChanges(bool subscribe)
{
if (subscribe)
{
object value = _source;
foreach (var prop in _properties)
{
prop.SubscribeToValueChange(value);
value = prop.GetValue(value);
if (value == null)
{
return;
}
}
}
else
{
foreach (var prop in _properties)
{
prop.UnsubsctribeToValueChange();
}
}
}
private void OnNestedPropertyChanged(PropertyChangeListener changedProperty)
{
ListenToPropertyChanges(false);
ListenToPropertyChanges(true);
var subscribers = _subscribers;
if (subscribers != null)
{
if (_synchContext != SynchronizationContext.Current)
{
_synchContext.Post(delegate { subscribers(this, new PropertyChangedEventArgs("Value")); }, null);
}
else
{
subscribers(this, new PropertyChangedEventArgs("Value"));
}
}
}
}
}
Try this:
Binding bind = new Binding("Text", myBindingListSource, "Current");
bind.Format += (s,e) => {
e.Value = e.Value == null ? "" : ((Person)e.Value).Name;
};
nameLabel.DataBindings.Add(bind);
I haven't tested it but it should work and I've been waiting for the feedback from you.
I stumbled across this by accident (four years after the original post), and after a quick read, I find that the accepted answer appears to be really over-engineered in respect to the OP's question.
I use this approach, and have posted an answer here to (hopefully) help anyone else who has the same problem.
The following should work (if infact this.myBindingListSource implements IBindingList)
I would just create a binding source to wrap my binding list (in my Form/View)
BindingSource bindingSource = new BindingSource(this.myBindingListSource, string.Empty);
And then just bind to the binding source like this:
nameLabel.DataBindings.Add(new Binding("Text", bindingSource, "Name"));
I think the OP's original code didn't work because there is no member called 'Current' on a BindingList (unless the OP has some sort of specialised type not mentioned).
I bound (at least i think i did) data to a ListBox following a tutorial. The class element I want bound has data in it but i see nothing on the ListBox after some event. I have the following partial XAML:
<ListBox x:Name="jukeBoxListBox" Height="227" VerticalAlignment="Top" ItemsSource="{Binding FilePathList}"/>
In the WPF form cs file I have. Should i set to class FolderItems or its attr filePathList? Also should I use ObservableCollection instead of list?
InitializeComponent();
FolderItems folderItems = new FolderItems();
this.DataContext = folderItems.FilePathList;
My data class:
class FolderItems : INotifyPropertyChanged
{
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected void Notify(string propertyName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion INotifyPropertyChanged implementation
private ObservableCollection<String> _pathList = new ObservableCollection<string>();
public ObservableCollection<String> FilePathList
{
get { return _pathList; }
set
{
if (value != _pathList)
{
_pathList = value;
Notify("FilePathList");
}
}
}
}
I think I need to mention that I change the List elements in a Button click event. Maybe the below is a part of the problem.
//in the event fItems is an instance of FolderItems
var files = new ObservableCollection<string>();
ProcessFiles(of.SelectedPath, files);
fItems.FilePathList = files;
//...
private void ProcessFiles(string path, ICollection<string> files)
{
foreach (var file in Directory.GetFiles(path).Where(name => name.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)))
files.Add(file);
foreach (var directory in Directory.GetDirectories(path))
ProcessFiles(directory, files);
}
I hail from Javaland and am brand new to C#. Please excuse my language.
If you'd change List<string> to ObservableCollection<string> (see here), your binding would get notified about changes in the list, e.g. when you add items.
Also, you must change the property name in the Notify call to filePathList.
And you should follow coding conventions for properties in .Net, which are usually written with a leading uppercase character. So your property would be FilePathList.
private ObservableCollection<String> pathList = new ObservableCollection<string>();
public ObservableCollection<String> FilePathList
{
get { return pathList; }
set
{
if (value != pathList)
{
pathList = value;
Notify("FilePathList"); // changed here
}
}
}
Change the binding to the renamed property:
<ListBox ... ItemsSource="{Binding FilePathList}"/>
See also Binding to Collections and Using Collection Objects as a Binding Source.
UPDATE
Your ProcessFiles method should be written as shown below to enable recursion.
private void ProcessFiles(string path, ICollection<string> files)
{
foreach (var file in Directory.GetFiles(path).Where(name => name.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)))
{
files.Add(file);
}
foreach (var directory in Directory.GetDirectories(path))
{
ProcessFiles(directory, files);
}
}
And be called like this:
var files = new ObservableCollection<string>();
ProcessFiles(of.SelectedPath, files);
var folderItems = new FolderItems();
folderItems.FilePathList = files;
DataContext = folderItems;
Or if you need to access the FolderItems object later (perhaps in some event handler) you might get it back from the DataContext:
DataContext = new FolderItems();
...
var folderItems = DataContext as FolderItems;
ProcessFiles(of.SelectedPath, folderItems.FilePathList);
try this.
I search for dll files insteed of mp3. you can change the pattern as you need.
public class FolderItems : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
//Temp Data
public FolderItems()
{
//Add System.windows.Form assampbly.
var dialog = new System.Windows.Forms.FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dialog.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK)
{
FilePathList = ProcessFiles(dialog.SelectedPath);
////var directories = new System.IO.DirectoryInfo("C:\\Windows\\").GetFiles().Select(x => x.Name);
//foreach (var file in directories)
//{
// FilePathList.Add(file);
//}
}
}
private ObservableCollection<String> ProcessFiles(string path)
{
string[] directories;
ObservableCollection<String> fileList = new ObservableCollection<string>();
var files = new System.IO.DirectoryInfo(path).GetFiles("*.dll").Select(x => x.Name); //Directory.GetFiles(path).Where(name => name.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase));
fileList = new ObservableCollection<String>(files.ToList<String>());
//your processing further
//directories = Directory.GetDirectories(path);
//foreach (string directory in directories)
//{
// // Process each directory recursively
// ProcessFiles(directory);
//}
return fileList;
}
protected void Notify(string propertyName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private ObservableCollection<String> _pathList = new ObservableCollection<string>();
public ObservableCollection<String> FilePathList
{
get { return _pathList; }
set
{
if (value != _pathList)
{
_pathList = value;
Notify("FilePathList");
}
}
}
}