ViewModel data not being found - c#

My project ViewModel elements are not being found. I'm trying to implement a ViewModel within my WPF Usercontrol. However, the binding isn't working properly and there appears to be no data. I'm trying to create a ViewModel to interact with, putting generic string arrays into, and various other bits of data.
MainWindow.xaml - (Usercontrol declaration)
<panels:FilterLister Grid.Column="0" x:Name="filter1FilterLister" />
MainWindows.cs - (Within the constructor, call to usercontrol
filter1FilterLister.Initialise(typeof(Genre));
FilterListViewModel.cs
public class FilterListViewModel
{
MyEntities context = new MyEntities();
ObservableCollection<string> entries = new ObservableCollection<string>();
public Type SelectedType;
private string p_TypeName;
public string TypeName
{
get { return p_TypeName; }
set {
//p_TypeName = value;
p_TypeName = SelectedType.Name.ToString();
}
}
public FilterListViewModel() { }
public FilterListViewModel(Type selectedType)
{
if (selectedType == typeof(Artist))
{
returnedArray = Artist.ReturnArtistNames(context);
}
// put together ObservableCollection
foreach (var str in returnedArray)
{
entries.Add(str);
}
SelectedType = selectedType;
}
}
FilterLister.xaml
<Label Name="labelToBind" Content="{Binding TypeName}" Grid.Row="0" />
FilterLister.cs
public partial class FilterLister : UserControl
{
FilterListViewModel filterListViewModel;
private MyEntities context;
public FilterLister()
{
InitializeComponent();
context = new MyEntities();
}
public void Initialise(Type objectType)
{
filterListViewModel = new FilterListViewModel(objectType);
this.DataContext = filterListViewModel;
}
}

Based on your code, TypeName is null so you saw nothing on the Label. From your code, I think you want to describe like:
public string TypeName
{
get{ return SelectedType.Name.ToString();}
}
As deryck suggested, you should add INotifyPropertyChanged interface for notification, but it should not affect binding at first time. If you believe ViewModel's data is correct but not populated on UI, you should check DataContext and Binding.

You've missed implement the INotifyPropertyChanged interface in your ViewModel, it's needed to the binded property can send "refresh message" to a UI.
Here is the interface, and how you can implement this:
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
public class FilterListViewModel : INotifyPropertyChanged
{
MyEntities context = new MyEntities();
ObservableCollection<string> entries = new ObservableCollection<string>();
public Type SelectedType;
private string p_TypeName;
public string TypeName
{
get { return p_TypeName; }
set {
//p_TypeName = value;
p_TypeName = SelectedType.Name.ToString();
NotifyPropertyChanged();
}
}
public FilterListViewModel() { }
public FilterListViewModel(Type selectedType)
{
if (selectedType == typeof(Artist))
{
returnedArray = Artist.ReturnArtistNames(context);
}
// put together ObservableCollection
foreach (var str in returnedArray)
{
entries.Add(str);
}
SelectedType = selectedType;
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Related

How to implement Inversion of control c# - wpf

I'm learning on how to implement inversion of control in the wpf application through the below link
https://www.codeguru.com/columns/experts/implementing-the-inversion-of-control-pattern-in-c.htm
The intent of the application is to load the data from table to combobox. The code works fine without any issue. So as a part of learning ooad design principle I thought below is the perfect case on which the highlevel module (Viewmodel) depend upon lowerlevel module (populatetab2combobox). I believe here we can apply dependency inversion. on reading online most of them started with inversion of control as a first step towards implementing Dependency inversion.
I just want to iterate that I don't have prior experience in oops principle. I might be wrong in my assumption. Please correct me if I'm wrong.
Window.xaml :
<ComboBox ItemsSource="{Binding populatecombobox.modeltogetusername}" Width="155" Margin="0,-20,-180,137">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding username}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
View Model :
Code without implementing inversion of control(This works fine without any issue):
//Class to populate the combobox
public class populatetab2combobox
{
public ObservableCollection<comboboxdata> modeltogetusername { get; set; }
public void getdatausinglinq()
{
using (Operations_Productivity_ToolEntities context = new Operations_Productivity_ToolEntities())
{
var a1 = from t1 in context.Test_ImportedAuditdata
select t1;
if (modeltogetusername == null)
modeltogetusername = new ObservableCollection<comboboxdata>();
foreach (var a in a1.GroupBy(x => x.username).Select(x => x.FirstOrDefault()))
{
modeltogetusername.Add(new comboboxdata
{
username = a.username.ToString()
});
}
}
}
}
public class ViewModel: INotifyPropertyChanged {
/** You can see that I'm calling viewModel class is depended with
populatetab2combobox. I believe this is the perfect case for implementing
Inversion of control **/
populatetab2combobox_populatecombobox = new populatetab2combobox();
private PopulateDatagrid _populatedatagridwithobservablecollection = new PopulateDatagrid();
private Loadfileintodatabase loaddata = new Loadfileintodatabase();
public PopulateDatagrid Populatedatagridwithobservablecollection {
get {
return _populatedatagridwithobservablecollection;
}
set {
if (value != _populatedatagridwithobservablecollection) {
_populatedatagridwithobservablecollection = value;
OnPropertyChanged("Populatedatagridwithobservablecollection");
}
}
}
DataModel dm = new DataModel();
public ViewModel() {
_populatecombobox.getdatausinglinq();
DoSomeThingCmd = new RelayCommand(o = >search());
_populatedatagridwithobservablecollection.getdatausinglinq();
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
Code with implementation of inversion of control(The issue is combobox is empty when i run when IOC implemented):
public interface INofificationAction
{
void getdatausinglinq();
}
public class populatetab2combobox : INofificationAction
{
public ObservableCollection<comboboxdata> modeltogetusername { get; set; }
public void getdatausinglinq()
{
using (Operations_Productivity_ToolEntities context = new Operations_Productivity_ToolEntities())
{
var a1 = from t1 in context.Test_ImportedAuditdata
select t1;
if (modeltogetusername == null)
modeltogetusername = new ObservableCollection<comboboxdata>();
foreach (var a in a1.GroupBy(x => x.username).Select(x => x.FirstOrDefault()))
{
modeltogetusername.Add(new comboboxdata
{
username = a.username.ToString()
});
}
}
}
}
public class implementingabstraction
{
INofificationAction _an;
public implementingabstraction(INofificationAction action)
{
this._an = action;
}
public void getdatausinglinq()
{
_an.getdatausinglinq();
}
}
public class ViewModel: INotifyPropertyChanged
{
INofificationAction getdata123 = new populatetab2combobox();
populatetab2combobox _populatecombobox = new populatetab2combobox();
public populatetab2combobox populatecombobox {
get {
return _populatecombobox;
}
set {
if (value != _populatecombobox) {
_populatecombobox = value;
OnPropertyChanged("populatetab2combobox");
}
}
}
public RelayCommand DoSomeThingCmd {
get;
set;
}
DataModel dm = new DataModel();
public ViewModel() {
implementingabstraction abs = new implementingabstraction(getdata123);
abs.getdatausinglinq();
DoSomeThingCmd = new RelayCommand(o = >search());
_populatedatagridwithobservablecollection.getdatausinglinq();
}
}
questions:
1) since I'm very new to oops based approach.Whether the above usecase is correct.
2) The above code is not working correctly. Can you please point out the mistake in my approach.

Can't bind to a member of a Model from a ViewModel

MyProduct is the model that has HasError boolean property (with OnPropertyChanged ...) that can change.
MyProductDialogViewModel is:
class ProductDialogViewModel : Notifier
{
public ProductDialogViewModel() { }
public MyProduct Product { get; set; }
public bool HasError
{
get { return Product.HasError; }
}
}
I have assigned MyProductDialogViewModel instance to BaseContentControl.DataContext to inflate a ContentControl.
This View can be inflated with different ViewModels all having HasError property using template binding.
<ContentControl x:Name="BaseContentControl" Content="{Binding}" ... >
Then I try to extract informations directly from its DataContext.
This don't work:
<Label Content="{Binding ElementName=BaseContentControl, Path=DataContext.HasError}"/>
But this works perfectly.
<Label Content="{Binding ElementName=BaseContentControl, Path=DataContext.Product.HasError}"/>
I tought it ca be a notifiy problem in the ViewModel so I have changed to this:
class ProductDialogViewModel : Notifier
{
public ProductDialogViewModel() { }
public MyProduct Product { get; set; }
public bool HasError
{
get { return Product.HasError; }
set
{
if (Product.HasError != value)
{
Product.HasError = value;
OnPropertyChanged("HasError");
}
}
}
}
but to no avail (in fact the set method is never called so it never notifies).
I don't want to directly refer to the specific Model instance cause the View can be inflated with different ViewModels.
How can I do ?
Thanks
You have to propagate the PropertyChanged event of MyProduct, i.e. subscribe to it and invoke OnPropertyChanged(nameof(HasError)) if HasError property of MyProduct being changed:
public class ProductDialogViewModel : Notifier
{
public ProductDialogViewModel() { }
private MyProduct _product = null;
public MyProduct Product
{
get { return _product; }
set
{
if (_product!=null)
{
_product.PropertyChanged -= Product_PropertyChanged;
}
_product = value;
if (_product != null)
{
_product.PropertyChanged += Product_PropertyChanged;
}
}
}
private void Product_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName==nameof(MyProduct.HasError))
{
OnPropertyChanged(nameof(HasError));
}
}
public bool HasError => Product.HasError;
}

WPF Binding Combobox to LINQ Populated Observable Collection

This is the first experience with WPF so please forgive me, I know this is pretty basic but I can't get it to work. I'm simply trying to bind a combobox to an LINQ to EF populated ObservableCollection. When I step through the code I see that the collection is populated, but the combo box doesn't display the contents of the collection.
Here is my ViewModel:
public class MainWindowViewModel : ViewModelBase
{
# region ObservableCollections
private ObservableCollection<Site> _sitescollection;
public ObservableCollection<Site> SiteCollection
{
get { return _sitescollection;}
set {
if (value == _sitescollection) return;
_sitescollection = value;
RaisePropertyChanged("SiteCollection");
}
}
# endregion
public MainWindowViewModel()
{
this.PopulateSites();
}
// Get a listing of sites from the database
public void PopulateSites()
{
using (var context = new Data_Access.SiteConfiguration_Entities())
{
var query = (from s in context.SITE_LOOKUP
select new Site(){Name = s.SITE_NAME, SeqId = s.SITE_SEQ_ID });
SiteCollection = new ObservableCollection<Site>(query.ToList());
}
}
}
My Site Class:
public class Site : INotifyPropertyChanged
{
#region Properties
string _name;
public string Name
{
get
{
return _name;
}
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
private int _seqid;
public int SeqId
{
get {
return _seqid;
}
set {
if (_seqid != value)
{
_seqid = value;
RaisePropertyChanged("SeqId");
}
}
}
#endregion
#region Constructors
public Site() { }
public Site(string name, int seqid)
{
this.Name = name;
this.SeqId = seqid;
}
#endregion
void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
And my XAML Bindings:
<ComboBox Margin="10"
ItemsSource="{Binding Sites}"
DisplayMemberPath="Name"
SelectedValuePath="SeqId" />
What am I doing wrong? Any assistance would be greatly appreciated.
You bound to path "Sites" but your property name was "SiteCollection".
You bind to properties, so the names have to match. Also make sure your data context is set to your view model object.

Changes in a viewmodel property is not being reflected in the UI

I am new in WPF I have implemented INotifyPropertyChanged interface. I have one viewmodel containing the property "TeamMemberList". The control executes the setter part, changes the property value but the PropertyChanged event remains null.
Here is code:
ViewModelBase:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ViewModel:(Which inherits the viewmodelbase)
Property is
public List<Employee> TeamMemberList
{
get
{
return _teamMemberList;
}
set
{
_teamMemberList = value;
NotifyPropertyChanged("TeamMemberList");
}
}
Binding
<ListBox Margin="10" ItemsSource="{Binding TeamMemberList, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" >
when new employee added to the DB, model reads it & creates List for all emplyee then the TeamMeberList property gets updated. This is updation method for TeamMemberList
var qryEmp = from employee in ClientModel.EmployeeList
where employee.ReportingManager == UserProfile.EmployeeId
select new Employee
{
EmployeeId = employee.EmployeeId,
EmployeeName = employee.EmployeeName,
Designation = employee.Designation,
ProfilePic = employee.ProfilePic,
};
TeamMemberList = qryEmp.ToList();
And implementation of Employee
public class Employee : ViewModelBase
{
private string _employeeName;
private string _employeeId;
private string _profilePic;
private string _designation;
private string _reportinManager;
public string EmployeeName
{
get
{
return _employeeName;
}
set
{
_employeeName = value;
NotifyPropertyChanged("EmployeeName");
}
}
public string EmployeeId
{
get
{
return _employeeId;
}
set
{
_employeeId = value;
NotifyPropertyChanged("EmployeeId");
}
}
public string ProfilePic
{
get
{
return _profilePic;
}
set
{
_profilePic = value;
NotifyPropertyChanged("ProfilePic");
}
}
public string Designation
{
get
{
return _designation;
}
set
{
_designation = value;
NotifyPropertyChanged("Designation");
}
}
public string ReportingManager
{
get
{
return _reportinManager;
}
set
{
_reportinManager = value;
NotifyPropertyChanged("ReportingManager");
}
}
}
It's hard to say what the problem is when we don't see more code (eg: how you are setting the DataContext etc...).
But there is an easy way to debug your bindings by adding the following attribute to it:
<ListBox Margin="10" ItemsSource="{Binding TeamMemberList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PresentationTraceSources.TraceLevel=High>
Adding this attribute will output the whole binding sequence to the Output window of Visual Studio. That should point out what is going wrong.
If you want to enable this for all bindings, you can also use the Visual Studio options:
Use ObserveableCollection instead of a list

Updating the View when items are added or removed from a bound ObservableCollection

I am currently writing a Windows 8.1 app that uses MVVM. I've stayed away from the model simply because I have never properly been able to update the View when data bound to the View changes. No number of websites or tutorials have been able to explain how to properly use INotifyPropertyChanged and I'm just lost at this point. I have the following class (including the method for adding an item of that type).
public class Organization
{
public Guid Id { get; set; }
public bool IsShared { get; set; }
public string Name { get; set; }
public ObservableCollection<Event> Events { get; set; }
public async static void Add(string Name)
{
Guid Id = Guid.NewGuid();
string FileName = Id.ToString() + ".txt";
var Folder = ApplicationData.Current.LocalFolder;
try
{
var Organizations = await Folder.CreateFolderAsync("Organizations", CreationCollisionOption.FailIfExists);
StorageFile File = await Organizations.CreateFileAsync(FileName, CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(File, JsonConvert.SerializeObject(new Organization { Id = Id, Name = Name, Events=new ObservableCollection<Event>() }));
}
catch
{
}
}
}
The following is my ViewModel:
public class OrganizationsViewModel : Base
{
private ObservableCollection<Organization> _List = new ObservableCollection<Organization>();
public ObservableCollection<Organization> List
{
get
{
Retrieve();
return _List;
}
set
{
}
}
public async void Retrieve()
{
var Folder = ApplicationData.Current.LocalFolder;
try
{
StorageFolder Organizations = await Folder.GetFolderAsync("Organizations");
var List = await Organizations.GetFilesAsync();
foreach (StorageFile i in List)
{
try
{
using (Stream s = await i.OpenStreamForReadAsync())
{
using (StreamReader sr = new StreamReader(s))
{
var item = JsonConvert.DeserializeObject<Organization>(await sr.ReadToEndAsync());
_List.Add(item);
}
}
}
catch
{
}
}
}
catch
{
}
}
}
The Base being:
public class Base : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
// property changed
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
What code do I need in my ViewModel and/or my class definition that will allow the View to properly update when items are added or removed from my ObservableCollection and more importantly why does that given code work? Thanks in advance!
With databinding View will automatically updated as long as it notified that properties it bound to has been changed. So what you need is to raise property changed event whenever binding source property value changed. For example :
public class OrganizationsViewModel : Base
{
private ObservableCollection<Organization> _List = new ObservableCollection<Organization>();
public ObservableCollection<Organization> List
{
get
{
Retrieve();
return _List;
}
set
{
if(_List != value)
{
_List = value;
NotifyPropertyChanged("List");
}
}
}
...
...
}
However, ObservableCollection should automatically notify View whenever item added to or removed from collection without you raise the event manually. So I am not 100% sure where is the problem in your code. Just try to call NotifyPropertyChanged on setter of every property and see if the problem solved. At least you know how to use INotifyPropertyChanged now :)

Categories