Issues with validating MVVM WPF Application - c#

I am trying to implement validation within a WPF application using MVVM, I believe that I have the validation set up correctly but when I test it it doesn't seem to give me a red outline on the text box as many examples I've found online do (Such as https://www.youtube.com/watch?v=OOHDie8BdGI).
For simplicity I have narrowed it down to one criterion which is that the textbox for Forename is not left blank and removed the other properties. The only difference I am aware of between the examples in guides I have been using and my own application is that my Model is held on a server whereas the View and ViewModel are client side, could this be what is causing the issues?
Any help would be greatly appreciated as I've been struggling with this for a few days now, thanks!
RegistrationModel (Server side)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Linq;
using System.Web;
namespace ScrumManagementWCFServices.Services.Registration
{
[DataContract]
public class RegistrationModel : IDataErrorInfo, INotifyPropertyChanged
{
private string forename;
[DataMember]
public string Forename
{
get
{
return forename;
}
set
{
forename = value;
NotifyPropertyChanged("Forename");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region IDataErrorInfo Members
string System.ComponentModel.IDataErrorInfo.Error
{
get { return null; }
}
string System.ComponentModel.IDataErrorInfo.this[string propertyName]
{
get
{
return GetValidationError(propertyName);
}
}
#endregion
#region Validation
static readonly string[] ValidatedProperties = {/* "Email", */"Forename"/*, "Surname", "Password", "ConPassword"*/};
public bool IsValid
{
get
{
foreach (string property in ValidatedProperties)
if (GetValidationError(property) != null)
return false;
return true;
}
}
string GetValidationError(String propertyName)
{
string error = null;
switch (propertyName)
{
case "Forename":
error = validateForename();
break;
}
return error;
}
private string validateForename()
{
if (String.IsNullOrWhiteSpace(Forename))
{
return "Customer name cannot be empty.";
}
return null;
}
}
}
RegistrationPage (View - Client side)
<Page x:Class="ScrumManagementApplication.Pages.LoginAndRegistrationPage.View.RegistrationPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ScrumManagementApplication.Pages.LoginAndRegistrationPage.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300"
Title="RegistrationView" Width="300">
<Page.Resources>
<local:RegistrationViewModel x:Key="DataContext"/>
</Page.Resources>
<Grid Background="#FFC0CAEC" DataContext="{StaticResource DataContext}" Margin="10">
<TextBox Text="{Binding RegistrationModel.Forename, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</Page>
RegistrationViewModel (Client side)
using ScrumManagementApplication.WCFRegistrationServiceReference;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.ComponentModel;
using ScrumManagementApplication.Pages.LoginAndRegistrationPage.View;
using System.Windows;
namespace ScrumManagementApplication.Pages.LoginAndRegistrationPage.ViewModel
{
public class RegistrationViewModel : INotifyPropertyChanged
{
public RegistrationViewModel()
{
RegistrationModel = new RegistrationModel()
{
Forename = "Rick"
};
}
public RegistrationModel RegistrationModel
{
get;
set;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
Thanks in advance!

You need to expose a wrapper property and implement IDataErrorInfo on the view model or bind to the model directly. Validation will not work with bindings like {Binding RegistrationModel.Forename}

You can simplify things a bit with the System.ComponentModel.DataAnnotations Namespace. For example, if you decorate your Forename property with a RequiredAttribute, you will see your required red error outline on your TextBox when the field is left empty:
[DataMember]
[Required(ErrorMessage="Customer name cannot be empty.")]
public string Forename
{
get
{
return forename;
}
set
{
Validator.ValidateProperty(value,
new ValidationContext(this, null, null) { MemberName = "Forename" });
forename = value;
NotifyPropertyChanged("Forename");
}
}
You can find out more details from the Using Data Annotations to Customize Data Classes page on MSDN. You could of course refactor this to use a single method that both validates and notifies the
INotifyPropertyChanged interface.

Related

Change value for anonymous property of type string

I'm working on an app written in WPF, the code is written in C#.
I have a question mark icon which when pressed suppose to set content to specific label.
The label content is binding to a property in the view model, lets call it 'NoneLegend'.
I want that property to clear itself after 5 second so I have a utility class that suppose to manage that. Inside that class I wrote an anonymous method that gets any type of property.
My question is how do I set that property to string.empty?
The method looks like this:
public static void EmptyStringAfterXseconds<T>(Expression<Func<T>> property)
{
var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
}
else
{
var t = propertyInfo.GetType();
propertyInfo.SetValue(null, "");
}
}
And I'm calling it like that:
NoneLegend = "Bla bla...";
Utils.EmptyStringAfterXseconds(() => NoneLegend);
How about this. I'm a bit worried about the new ResetAfterTime() call. Don't know if the instance is around long enough. It might be collected by the Garbage Collector before the Timer fires. Would have to think about that but it seems to work fine.
A Notifier class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace WpfApp1
{
public class PropertyNotifier : INotifyPropertyChanged
{
public void NotifyPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
// The view automatically fills the PropertyChanged event
public event PropertyChangedEventHandler PropertyChanged;
}
}
The Viewmodel:
using System.ComponentModel;
using System.Threading;
namespace WpfApp1
{
public class ViewModel : PropertyNotifier
{
public ViewModel(string legend)
{
Legend = legend;
}
private string _Legend;
/// <summary>
/// Here's where the magic happens
/// </summary>
public string Legend
{
get => _Legend;
set
{
_Legend = value;
new ResetAfterTime<string>(this, () => Legend, value);
}
}
}
}
And your enhanced routine:
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
namespace WpfApp1
{
public class ResetAfterTime<T>
where T : class
{
Timer _timer;
PropertyInfo _propertyInfo;
PropertyNotifier _notifier;
int _due;
public ResetAfterTime(PropertyNotifier notifier, Expression<Func<T>> property, T value, int due = 3000)
{
_notifier = notifier;
_propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
_due = due;
if (_propertyInfo == null)
{
throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
}
else
{
if (value != default)
{
StartTimer();
}
}
}
private void StartTimer()
{
_timer = new Timer(MakeDisappear, null, _due, _due);
}
private void StopTimer()
{
_timer.Dispose();
_timer = null;
}
private void MakeDisappear(object state)
{
SetValue(null);
StopTimer();
}
private void SetValue(object value)
{
var t = _propertyInfo.GetType();
_propertyInfo.SetValue(_notifier, value);
_notifier.NotifyPropertyChanged(_propertyInfo.Name);
}
}
}
For the binding in the view to know what has changed you need to notify it about that change. The INotifyProperyChanged interface was designed for that purpose. In the code below in the ViewModel this interface is implemented.
I've created a simple WPF program. Here's the MainWindow:
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel>
<Label x:Name="Legend" Content="{Binding Legend}"></Label>
</StackPanel>
</Grid>
</Window>
And the code behind:
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel("Text should disappear");
}
}
}
And the ViewModel:
using System.ComponentModel;
using System.Threading;
namespace WpfApp1
{
public class ViewModel : INotifyPropertyChanged
{
Timer LegendTimer;
public ViewModel(string legend)
{
Legend = legend;
}
private void StartLegendTimer()
{
LegendTimer = new Timer(MakeDisappear, null, 3000, 3000);
}
private void StopLegendTimer()
{
LegendTimer.Dispose();
LegendTimer = null;
}
private void MakeDisappear(object state)
{
Legend = string.Empty;
StopLegendTimer();
}
private string _Legend;
/// <summary>
/// Here's where the magic happens
/// </summary>
public string Legend
{
get => _Legend;
set
{
// Each time the value is set ...
_Legend = value;
// we notify the view that a value has changed
NotifyPropertyChanged(nameof(Legend));
// If the value is not null or empty
if(!string.IsNullOrWhiteSpace(value))
{
// We start the time
StartLegendTimer();
}
}
}
private void NotifyPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
// The view automatically fills the PropertyChanged event
public event PropertyChangedEventHandler PropertyChanged;
}
}

C# condense redundant code in class with INotifyPropertyChange

I've been reading a few articles the past few days on inheriting classes and creating base classes, which i often do in tools I've written. However I specifically was looking into ways to reduce the redundant code often written in my classes which contain INotifyPropertyChange. Normally my classes look something like this, inheriting the base class of NotifyBase. However I've seen here a there in various scripts people moving some of the Get and Set code into the base class. I wanted to know what things to look out for when doing this? is this bad practice or good practice? Does the example I provided written correctly to do so?
One benefit being the Get and Set are much simpler in the classes which inherit NotifyBase in the new setup.
Current Setup Example
FileItem Class
using System.IO;
namespace WpfApplication1
{
public class FileItem : NotifyBase
{
private string _fullPath;
public string FullPath
{
get { return this._fullPath; }
set
{
this._fullPath = value;
this.NotifyPropertyChanged("FullPath");
}
}
}
}
Base Class 'NotifyBase'
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WpfApplication1
{
public class NotifyBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Possible New Setup
FileItem Class
using System.IO;
namespace WpfApplication1
{
public class FileItem : NotifyBase
{
public string FullPath
{
get { return Get<string>(); }
set { Set(value); }
}
}
}
Base Class 'NotifyBase'
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Varo.Helper
{
public class NotifyBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
private readonly Dictionary<string, object> _propertyValues;
protected NotifyBase()
{
_propertyValues = new Dictionary<string, object>();
}
protected void Set<T>(T value, [CallerMemberName] string name = "")
{
if (_propertyValues.ContainsKey(name))
{
_propertyValues[name] = value;
NotifyPropertyChanged(name);
}
else
{
_propertyValues.Add(name, value);
NotifyPropertyChanged(name);
}
}
protected T Get<T>([CallerMemberName] string name = "")
{
if (_propertyValues.ContainsKey(name))
{
return (T)_propertyValues[name];
}
return default(T);
}
}
}
Check the PropertyChanged.Fody NuGet
Weaves .NET assembly at compile time so properties declared as
public int Property { get; set; }
Gets compiled as
private int property;
public int Property
{
get
{
return property;
}
set
{
if(property != value)
{
property = value;
if (this.PropertyChanged!= null) PropertyChanged(this, new PropertyChangedEventArgs("Property");
}
}
}

WPF frame content not updating when source Uri is changed through binding

I've been working on this issue for a few days and can't seem to find anything that will work for my application.
My issue is that I am trying to use a User Control containing buttons to bind to commands which change the source Uri of a frame (both displaying in the same window). When I click a button it is changing the Uri within the ViewModel but the frame does not change the page to reflect this. I believe that it is either not picking up the change due to the way it is binding or there is something blocking it from changing the page which is displaying in the frame.
I am using the MVVM pattern which has been great until I reached the point that I had to start dealing with navigation. Any help would be greatly appreciated!
Navigation User Control View Buttons:
<Button Name="BtnMainDash" Content="Main Dashboard" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="180" Command="{Binding MainDashboard}"/>
<Button Name="BtnAccount" Content="Account" HorizontalAlignment="Left" Margin="10,40,0,0" VerticalAlignment="Top" Width="180" Command="{Binding EditAccount}"/>
<Button Name="BtnProjects" Content="Projects" HorizontalAlignment="Left" Margin="10,70,0,0" VerticalAlignment="Top" Width="180" Command="{Binding ProjectScreen}"/>
Main Window Frame:
<Frame x:Name="FmePages" Margin="200,30,-0.4,0.4"
Source="{Binding Path=CurrentPage, Mode=OneWay, UpdateSourceTrigger=PropertyChanged }"
NavigationUIVisibility="Hidden"/>
Button ICommands (All the same except that each calls a difference Uri changing command):
using System;
using System.Windows.Input;
using ScrumManagementApplication.Pages.MainWindow.ViewModel;
namespace ScrumManagementApplication.Pages.MainWindow.Commands
{
class LoadEditAccount : ICommand
{
private readonly NavigationViewModel _navigationViewModel;
public LoadEditAccount(NavigationViewModel navigationViewModel)
{
_navigationViewModel = navigationViewModel;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return _navigationViewModel.CommandsEnabled;
}
public void Execute(object parameter)
{
_navigationViewModel.LoadEditAccount();
}
}
}
ViewModel:
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using ScrumManagementApplication.Pages.MainWindow.Commands;
using ScrumManagementApplication.SessionData;
using MessageBox = System.Windows.MessageBox;
namespace ScrumManagementApplication.Pages.MainWindow.ViewModel
{
public class NavigationViewModel : INotifyPropertyChanged, INotifyPropertyChanging
{
public bool CommandsEnabled = false;
public NavigationViewModel()
{
MainDashboard = new LoadMainDashboard(this);
EditAccount = new LoadEditAccount(this);
ProjectScreen = new LoadProjectScreen(this);
LogOut = new LoadLogOut(this);
CommandsEnabled = true;
LoadEditAccount();
}
#region ICommands
public ICommand MainDashboard { get; private set; }
public void LoadMainDashboard()
{
_currentPage = null;
_currentPage = new Uri("pack://application:,,,/Pages/MainWindow/View/MainDashboardView.xaml", UriKind.Absolute);
}
public ICommand EditAccount { get; private set; }
public void LoadEditAccount()
{
_currentPage = null;
_currentPage = new Uri("pack://application:,,,/Pages/EditUserDetailsPage/View/EditUserDetailsView.xaml", UriKind.Absolute);
}
public ICommand ProjectScreen { get; private set; }
public void LoadProjectScreen()
{
_currentPage = null;
_currentPage = new Uri("pack://application:,,,/Pages/ProjCreationPage/View/ProjectCreationPage.xaml", UriKind.Absolute);
}
public ICommand LogOut { get; private set; }
public void LoadLogOut()
{
var dialogResult = MessageBox.Show("Are you sure you want to log out?", "Log Out", MessageBoxButton.YesNo);
if (dialogResult == (MessageBoxResult) DialogResult.Yes)
{
App.Current.Shutdown();
}
}
#endregion // ICommands
#region MainFrame
private Uri _currentPage;
public Uri CurrentPage
{
get { return _currentPage; }
set
{
_currentPage = value;
OnPropertyChanged("CurrentPage");
}
}
#endregion // MainFrame
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion // INotifyPropertyChanged Members
public event PropertyChangingEventHandler PropertyChanging;
protected void OnPropertyChanging(String propertyName)
{
PropertyChangingEventHandler handler = PropertyChanging;
if (handler != null)
{
handler(this, new PropertyChangingEventArgs(propertyName));
}
}
}
}
Any & all help appreciated, even if it doesn't fully solve my issue anything that helps me get closer to a solution is good!
Thanks in advance
Instead of doing this
_currentPage = //some value;
do this:
CurrentPage = //some value
The event will be raised when you change the property and not the backing field.
EDIT
One more suggestion is to create a single command class since all your commands are setting a string value to a property. You can get the button name using the CommandParameter. Based on that set the Uri.
Got a similar Problem, had a mainwindow with a frame in it and when I, for example, opened an openfiledialog and closed it, this frame (some others too) did not update even if I called PropertyChanged() and the bound Property had the right value. The only solution for me was to remove the binding and handle the Content with NavigationService instead. If you need this Property you bound to for some other approaches you could do something like:
private Page _dataExplorerContent;
public Page DataExplorerContent
{
get { return _dataExplorerContent; }
set
{
if(value != null)
{
contentFrame.Navigate(value)
SetField(ref _dataExplorerContent, value);
}
}
}

Dynamic Binding is not updating

I'm a beginner in wpf. I am following a textbook to learn, the examples are shown but its not working whenever I am writing dynamic binding part even after following each of its instructions strictly thrice.
this is the code behind
using System;
using System.ComponentModel;
namespace KarliCards_GUI
{
[Serializable]
public class GameOptions:INotifyPropertyChanged
{
private bool _playAgainstComputer = false;
public bool PlayAgainstComputer
{
get
{
return _playAgainstComputer;
}
set
{
_playAgainstComputer = value;
OnPropertyChanged("PlayAgainstComputer");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In XAML file I want to dynamically bind IsChecked property of a checkbox by using DataContext which will have an instance of GameOptions.
Below part of code is in XAML file
<CheckBox Content="Play against computer" HorizontalAlignment="Left" Margin="11,33,0,0" VerticalAlignment="Top" Name="playAgainstComputerCheck" IsChecked="{Binding Path=PlayAgainstComputer}" />
and below is the code of csharp file of that XAML
namespace KarliCards_GUI
{
public partial class Options : Window
{
private GameOptions _gameOptions;
public Options()
{
if (_gameOptions == null)
{
if (File.Exists("GameOptions.xml"))
{
using (var stream = File.OpenRead("GameOptions.xml"))
{
var serializer = new XmlSerializer(typeof(GameOptions));
_gameOptions = serializer.Deserialize(stream) as GameOptions;
}
}
else
_gameOptions = new GameOptions();
}
DataContext = _gameOptions;
InitializeComponent();
}
}
}
The problem I am facing is, in the property 'PlayAgainstComputer', in set part if I set the variable(_playAgainstComputer) as 'value' it is always checked in the checkbox.
Might be the case the since the InitializeComponent() method is being called after the DataContext is set.
The default value for IsChecked property of CheckBox is true. I suggest first to call the InitializeComponent() method and then set the DataContext.

WPF MVVM with Entity Framework?

I'm building a simple mvvm WPF app in VS2010 .NET4.0 with Entity Framework 4. I'm a WPF beginner with only 1 year's programming experience. Trying to bind a datagrid in my XAML to an Entity Framework model. I have an observable collection in my View Model but can't seem to read the data in?
I have an Entity Framework .edmx included in the project which holds a single 'tbCountrys' table with a primary ID.
Here's my model class which just declares some variables/properties related to columns in my table and implements INotifyPropertyChanged:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace Entity_MVVM
{
public class CountrysModel : INotifyPropertyChanged
{
#region variables
private string _CountryId;
private string _ShortName;
private string _LongName;
# endregion
# region Properties
public string CountryId
{
get { return _CountryId; }
set { _CountryId = value;
OnPropertyChanged("CountryId");
}
}
public string ShortName
{
get { return _ShortName; }
set
{
_ShortName = value;
OnPropertyChanged("ShortName");
}
}
public string LongName
{
get { return _LongName; }
set
{
_LongName = value;
OnPropertyChanged("LongName");
}
}
#endregion
# region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
# endregion
}
}
My View Model also implements INotifyPropertyChanged, declares an Observable Collection to store my query results and has a LoadGrid() method which should query my table with an EntityConnection and populate the Observable Collection. This doesn't seem to be working? I am invoking the LoadGrid() method from the constructor of my View Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data.EntityClient;
using System.Data;
using System.Windows;
using System.Collections;
namespace Entity_MVVM
{
public class CountrysViewModel : INotifyPropertyChanged
{
#region Constructor
public CountrysViewModel()
{
LoadGrid();
}
# endregion
# region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
# endregion
# region ObservableCollection
private ObservableCollection<CountrysModel> _CountrysModelObservableList = new ObservableCollection<CountrysModel>();
public ObservableCollection<CountrysModel> CountrysModelObservableList
{
get { return _CountrysModelObservableList; }
set
{
_CountrysModelObservableList = value;
OnPropertyChanged("CountrysModelObservableList");
}
}
# endregion
# region Properties
private CountrysModel _CountrysModelView;
public CountrysModel CountrysModelView
{
get { return _CountrysModelView; }
set
{
_CountrysModelView = value;
OnPropertyChanged("CountrysModel");
}
}
# endregion
# region LoadGrid Method
public void LoadGrid()
{
LDBEntities db = new LDBEntities();
using (var conn = new EntityConnection("name=LDBEntities"))
{
conn.Open();
EntityCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT * FROM LDBEntities.tbCountrys";
try
{
EntityDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection);
_CountrysModelObservableList.Clear();
while (rdr.Read())
{
var cCountryId = rdr["CountryId"].ToString();
var cShortName = rdr["shortName"].ToString();
var cLongName = rdr["longName"].ToString();
_CountrysModelView = new CountrysModel()
{
CountryId = cCountryId,
ShortName = cShortName,
LongName = cLongName
};
_CountrysModelObservableList.Add(_CountrysModelView);
}
}
catch
{
MessageBox.Show(string.Format("Can't read in data!"));
}
}
#endregion
}
}
}
Lastly, my XAML view:
<Window x:Class="Entity_MVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Entity_MVVM"
Title="MainWindow" Height="350" Width="525"
DataContext="{DynamicResource MyViewModel}">
<Window.Resources>
<vm:CountrysViewModel x:Key="MyViewModel"/>
</Window.Resources>
<Grid>
<DataGrid Width="400" Height="127" Name="grdPublications" ItemsSource="{Binding Path=CountrysModelObservableList}">
</DataGrid>
</Grid>
</Window>
When I debug the code, the try block in my VIew Model is not executed and the catch exception is thrown. My while loop to read in the data never runs as it bails out after I declare the EntityDataReader object. Maybe there is something not quite right with my query syntax?
Any help would be most appreciated as I can't find many examples online of using the Entity Framework with MVVM. Thanks
Also, getting this exception in the XAML, can't create an instance of my View Model. The connection string is correct in the App.config so not sure what's causing it...
You connection string looks really wrong.
The code is failing on the EntityConnection constructor
at System.Data.EntityClient.EntityConnection.ctor(String connectionString)
So it is this line :
new EntityConnection("name=LDBEntities")
What sort of connection string is that "name=LDBEntities" ?
I think you have forgotten to get the connection string from your ressource file.
new EntityConnection(SomeResource.LDBEntities)

Categories

Resources