Wrappanel Not Updating After Drag&Drop Files - c#

I have a View that has ItemsControl and Wrappanel inside it. By using Drag&Drop files I am trying to update the Wrappanel. I have all data related to files in a JsonFile. There is no problem with appending data to json file. It is working. When I redebug the solution I can see the list of files in Wrappanel.
public partial class StorageView : Window
{
readonly StorageViewModel _storageViewModel;
public StorageView()
{
_storageViewModel = new StorageViewModel();
InitializeComponent();
}
private void TopMenuBorder_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.DragMove();
}
}
// Wrappanel Drop
private void StorageBrowser_Drop(object sender, DragEventArgs e)
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
List<string> files2 = new List<string>();
foreach (var file in files)
{
files2.Add(file);
}
_storageViewModel.TempFiles = files2;
}
// Drag Enter
private void StorageBrowser_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effects = DragDropEffects.Move;
else
e.Effects = DragDropEffects.None;
}
private void CreateNewFolder_Click(object sender, RoutedEventArgs e)
{
}
}
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical">
<Button Command="{Binding AddFileCommand}" Content="Add File"/>
<ItemsControl ItemsSource="{Binding Files, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Name="StorageBrowser" Background="White" Drop="StorageBrowser_Drop" DragEnter="StorageBrowser_DragEnter" VerticalAlignment="Stretch" AllowDrop="True" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding FileName}"/>
<!--<comp:FileCard/>-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
public class StorageViewModel : Screen, INotifyPropertyChanged
{
#region Commands
private ICommand _addFileCommand;
private bool canExecute = true;
public bool CanExecute
{
get
{
return this.canExecute;
}
set
{
if (this.canExecute == value)
{
return;
}
this.canExecute = value;
}
}
public ICommand AddFileCommand
{
get
{
return _addFileCommand;
}
set
{
_addFileCommand = value;
}
}
#endregion
#region Notify
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region FileModel
private int _id;
private string _fileName;
private string _fullFileName;
private decimal _fileSize;
private string _fileType;
private string _fileIcon;
private string _fileExtension;
private string _fileSizeType;
private string _fileImage;
private string _fullFileSize;
private string _fileOwner;
private DateTime? _created;
private DateTime? _modified;
private DateTime? _lastAccessed;
private bool _isVersionFile;
private List<FileModel> _fileVersions;
public List<FileModel> FileVersions
{
get { return _fileVersions; }
set { _fileVersions = value; OnPropertyChanged(nameof(FileVersions)); }
}
public bool IsVersionFile
{
get { return _isVersionFile; }
set { _isVersionFile = value; OnPropertyChanged(nameof(IsVersionFile)); }
}
public DateTime? LastAccess
{
get { return _lastAccessed; }
set { _lastAccessed = value; OnPropertyChanged(nameof(LastAccess)); }
}
public DateTime? Modified
{
get { return _modified; }
set { _modified = value; OnPropertyChanged(nameof(Modified)); }
}
public DateTime? Created
{
get { return _created; }
set { _created = value; OnPropertyChanged(nameof(Created)); }
}
public string FileOwner
{
get { return _fileOwner; }
set { _fileOwner = value; OnPropertyChanged(nameof(FileOwner)); }
}
public string FullFileSize
{
get { return _fullFileSize; }
set { _fullFileSize = value; OnPropertyChanged(nameof(FullFileSize)); }
}
public string FileImage
{
get { return _fileImage; }
set { _fileImage = value; OnPropertyChanged(nameof(FileImage)); }
}
public string FileSizeType
{
get { return _fileSizeType; }
set { _fileSizeType = value; OnPropertyChanged(nameof(FileSizeType)); }
}
public string FileExtension
{
get { return _fileExtension; }
set { _fileExtension = value; OnPropertyChanged(nameof(FileExtension)); }
}
public string FileIcon
{
get { return _fileIcon; }
set { _fileIcon = value; OnPropertyChanged(nameof(FileIcon)); }
}
public string FileType
{
get { return _fileType; }
set { _fileType = value; OnPropertyChanged(nameof(FileType)); }
}
public decimal FileSize
{
get { return _fileSize; }
set { _fileSize = value; OnPropertyChanged(nameof(FileSize)); }
}
public string FullFileName
{
get { return _fullFileName; }
set { _fullFileName = value; OnPropertyChanged(nameof(FullFileName)); }
}
public string FileName
{
get { return _fileName; }
set { _fileName = value; OnPropertyChanged(nameof(FileName)); }
}
public int Id
{
get { return _id; }
set { _id = value; OnPropertyChanged(nameof(Id)); }
}
#endregion
#region Collections
private List<string> _tempFiles { get; set; }
public List<string> TempFiles { get { return _tempFiles; } set { _tempFiles = value; OnPropertyChanged("TempFiles"); } }
private ObservableCollection<FileModel> _files { get; set; }
public ObservableCollection<FileModel> Files { get { return _files; } set { _files = value; OnPropertyChanged("Files"); } }
#endregion
public StorageViewModel()
{
AddFileCommand = new RelayCommand(AddFile, param=>this.canExecute);
Files = new ObservableCollection<FileModel>(Documentive.GCS.DataAccess.GCSDataAccess.GetDataFromJson());
}
public void AddFile(object o)
{
foreach (var file in TempFiles)
{
Documentive.GCS.DataAccess.GCSDataAccess.AppendDataToFileJson(file);
}
Files.Clear();
Files = Documentive.GCS.DataAccess.GCSDataAccess.GetDataFromJson();
}
}
There is all my codes. I need to update ItemsControl and list new files' data in wrappanel. There is no problem with the FileCard UserControl, I just tried to list data by using label.(just a test)
I don't know if there is a problem with Drag&Drop event and its codes or not.
Thanks.

I think you might actually have a few problems here.
First of all, implement DragOver instead of DragEnter, otherwise you won't be able to drop files into it.
Secondly, get rid of the ScrollViewer, and let ItemsControl manage the scrolling itself. There are a number of reasons for this (not the least of which is virtualization), but just trust me: never put an ItemsControl inside a ScrollViewer.
Next, get rid of the vertical StackPanel. By placing everything in a stack panel you're making your ItemsControl size itself according to the number of items it's already bound to, so dropping files into that big blank area underneath it won't do anything. Set your WrapPanel's background to a color you can actually see, and make sure it's covering the area of the page you think it is. Best way to do that is to use a parent Grid to do layout and then populate that with your Button and ItemsControl, setting your alignment properties accordingly.
The biggest problem with this code though is that your TopMenuBorder_MouseDown handler is updating TempFiles, but your ItemsControl is binding to Files.

Related

Telerik datagrid Refresh data: Button in view is working but event not

I struggle to refresh the data attached to the RADdatagrid. The view with the Datagrid shows the position of a team in a competition. Every time a new game is finished the view has to be updated automatically. The data is stored in a sqlite database and a simple sql query gets the positions from the database. A button in the view that calls the query method does the job but I want to update the grid directly after the finished game is stored. I implemented INotifyPropertyChanged but no result. I also tried to fire the button_click event but that also didn't bring me the result. I want to do this right but I am open to a quick and dirty solution. Here is a bit of my code:
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock Grid.Row="2" Margin="40,0,0,5">Team Ranking</TextBlock>
<Button x:Name="RefreshViewButton" Command="{Binding Path=RefreshView}" Margin="40 0 0 0 " Click="RefreshViewButton_Click">Refresh</Button>
</StackPanel>
<StackPanel Grid.Row="6" Margin="0, 0, 50, 0" VerticalAlignment="Stretch">
<telerikGrid:RadDataGrid
AutoGenerateColumns="False"
x:Name="Datagrid"
BorderThickness="0"
ItemsSource="{x:Bind ViewModel.TeamResult, Mode=TwoWay}"
ColumnDataOperationsMode="Flyout"
GridLinesVisibility="None"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
UserEditMode="None" >
<telerikGrid:RadDataGrid.Columns>
<telerikGrid:DataGridNumericalColumn PropertyName="Rank" Header="Rank" SizeMode="Auto"/>
<telerikGrid:DataGridTextColumn PropertyName="Team_Naam" Header="TeamNaam" SizeMode="Auto"/>
<telerikGrid:DataGridTextColumn PropertyName="WedstrijdPunten" Header="WP" CanUserEdit="False" CanUserFilter="False" CanUserGroup="False" CanUserReorder="False" CanUserResize="False" CanUserSort="False" SizeMode="Auto" />
<telerikGrid:DataGridTextColumn PropertyName="PuntenVoor" Header="GP" SizeMode="Auto"/>
</telerikGrid:RadDataGrid.Columns>
</telerikGrid:RadDataGrid>
</StackPanel>
This is my view:
public sealed partial class TeamTotals : Page
{
public TeamResultsViewModel ViewModel { get; set; } = new TeamResultsViewModel();
public TeamTotals()
{
DataContext = ViewModel;
this.InitializeComponent();
}
public void RefreshViewButton_Click(object sender, RoutedEventArgs e)
{
ViewModel.LoadTeamResultsData();
}
}
My ViewModel:
public class TeamResultsViewModel : TeamModel
{
//public List<TeamModel> TeamResult = new List<TeamModel>();
public ObservableCollection<TeamModel> TeamResult = new ObservableCollection<TeamModel>();
TeamModel tm = new TeamModel();
public TeamResultsViewModel()
{
LoadTeamResultsData();
tm.PropertyChanged += Tm_PropertyChanged;
}
private void Tm_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
throw new NotImplementedException();
}
public void LoadTeamResultsData()
{
int i = 0;
if(TeamResult != null)
{
TeamResult.Clear();
}
try
{
string sql = "Select Team_Naam, WedstrijdPunten, PuntenVoor, PuntenTegen FROM Team WHERE KlasseId = 1 " +
"ORDER BY WedstrijdPunten DESC, PuntenVoor DESC LIMIT 10;";
var resultaat = SqliteDataAccess.LoadData<TeamModel>(sql, new Dictionary<string, object>());
foreach (var x in resultaat)
{
TeamResult.Add(x);
x.Rank = i++;
}
}
catch (Exception ex)
{
var messagedialog2 = new MessageDialog($"{ex}");
_ = messagedialog2.ShowAsync();
}
return;
}
}
and the model:
public class TeamModel : INotifyPropertyChanged
{
private int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
private int _klasseId;
public int KlasseId
{
get { return _klasseId; }
set { _klasseId = value; }
}
private string _team_naam;
public string Team_Naam
{
get { return _team_naam; }
set { _team_naam = value; }
}
private int _coachId;
public int CoachId
{
get { return _coachId; }
set { _coachId = value; }
}
private int _clubId;
public int ClubId
{
get { return _clubId; }
set { _clubId = value; }
}
private int _puntenVoor;
public int PuntenVoor
{
get { return _puntenVoor; }
set { _puntenVoor = value; }
}
private int _puntenTegen;
public int PuntenTegen
{
get { return _puntenTegen; }
set { _puntenTegen = value; }
}
private int _wedstrijdPunten;
public int WedstrijdPunten
{
get { return _wedstrijdPunten; }
set
{
_wedstrijdPunten = value;
OnPropertyChanged("WedstrijdPunten");
}
}
private int _rank;
public int Rank
{
get { return _rank; }
set { _rank = value; }
}
public List<SpelerModel> TeamLeden { get; set; } = new List<SpelerModel>();
public string Standen => $"{Team_Naam} : {PuntenVoor}";
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public override string ToString()
{
return Standen;
}
}

Xamarin - Picker Selected Item not changing

I am trying to bind a Picker in Xamarin.
My HTML Code
<Picker Title="Select a coin"
ItemsSource="{Binding Coins}"
ItemDisplayBinding="{Binding Short_Name}"
SelectedItem="{Binding SelectedCoin,Mode=TwoWay}" />
<Label Text="{Binding SelectedCoin.Short_Name}" /> //This does not
change when I change the item in the picker.
Here is my code In the ViewModel
public class Currency
{
public string Short_Name { get; set; }
public string Image_Url { get; set; }
}
Currency selectedCoin;
public ObservableCollection<Currency> _coins = new
ObservableCollection<Currency>();
public Currency SelectedCoin
{
get { return selectedCoin; }
set
{
if (selectedCoin != value)
{
selectedCoin = value;
OnPropertyChanged();
}
}
}
public ObservableCollection<CryptoCurrency> Coins
{
get
{
return _coins;
}
set
{
SetObservableProperty(ref _coins, value);
}
}
public async void GetCoins()
{
Currency c = new Currency();
coinsPageModel.Coins = await coinsPageModel.GetCoins();
foreach (var item in coinsPageModel.Coins)
{
c.Short_Name = item.Short_Name;
Coins.Add(c);
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
I have tried several different ways and I just cannot seem to change the text in the label below the picker when I change the picker item. Any help or help is much appreciated!
You should raise the property change every time SelectedItem change, like this:
private ObservableCollection<Currency> _coins = new ObservableCollection<Currency>();
public ObservableCollection<CryptoCurrency> Coins
{
get
{
return _coins;
}
set
{
SetObservableProperty(ref _coins, value);
}
}
private Currency selectedCoin;
public Currency SelectedCoin
{
get { return selectedCoin; }
set
{
if (selectedCoin != value)
{
selectedCoin = value;
RaisePropertyChanged(() => this.SelectedCoin);
}
}
}
Your XAML seems correct.
Currency c = new Currency();
Inside of GetCoins, should be placed inside the foreach loop.

WPF Binding Object

I have a little problem with a ListBox and his binding.
All is good except when I call the function LstExtensionUnSelectAll() because
nothing changed, the checkbox are again checked.
I think it's a stupid thing but I don't see it.
<ListBox ItemsSource="{Binding LstExtension, Mode=TwoWay}" Grid.Row="0">
<ListBox.ItemTemplate>
<HierarchicalDataTemplate>
<CheckBox Content="{Binding Extension}" IsChecked="{Binding Checked}"/>
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here it's the object LstExtension :
public class CustomExtensions
{
public string Extension { get; set; }
public bool Checked { get; set; }
public CustomExtensions(string ext)
{
Extension = ext;
Checked = true;
}
}
private List<CustomExtensions> _LstExtension;
public IEnumerable<CustomExtensions> LstExtension
{
get { return _LstExtension; }
set
{
if (value != _LstExtension)
{
_LstExtension = value.ToList();
NotifyPropertyChanged("LstExtension");
}
}
}
internal void LstExtensionUnSelectAll()
{
_LstExtension?.ForEach(c => c.Checked = false);
NotifyPropertyChanged("LstExtension");
}
you need to update your CustomExtensions class to use INotifyPropertyChanged so that Checked raises the event whenever the value changes.
public class CustomExtensions : INotifyPropertyChanged
{
public string Extension { get; set; }
private bool _checked;
public bool Checked
{
get { return _checked; }
set
{
if (_checked == value) return;
_checked = value;
RaisePropertyChanged("Checked");
}
}
public CustomExtensions(string ext)
{
Extension = ext;
Checked = true;
}
public virtual event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string name)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}

Property changed event is not getting fired wpf

I have to change the value in a text box dynamically, on selecting a value from a combox box, which is present in different view. when changing the dependency property's source, the propertychangedEventHandler value is not changing, i.e it is remaining as null, so the event is not getting fired. As a result the text in the textbox is not changing. Below is the code. I have bound the text in textbox to _name property.
public partial class Details : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string name = "";
public Details()
{
InitializeComponent();
Name = Connector.Name;
DataContext = this;
}
public string Name
{
get { return name; }
set
{
name = value; OnPropertyChanged("Name");
}
}
protected void OnPropertyChanged(string s)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(s));
}
}
}
Xaml code
<StackPanel Orientation="Vertical">
<TextBlock Text="Student Details" VerticalAlignment="Top" HorizontalAlignment="Center" FontSize="16" FontWeight="Bold"> </TextBlock>
<StackPanel Margin="0,5" Orientation="Horizontal" >
<Label MinWidth="100" MaxWidth="110">Name:</Label>
<Border BorderBrush="Gray" BorderThickness="2">
<TextBox Name="nametextbox" Text="{Binding Name,Mode=TwoWay}" Width="auto" MinWidth="100" FontWeight="Black"></TextBox>
</Border>
</StackPanel>
Is it possible that you accidentally exchanged name and _name, using name in XAML for the binding?
Usually you have a public property with a capitalized name, and a private field with a non-capitalized name, optionally prefixed with an underscore as you did.
So, you should have
public string Name {
get { return _name; }
set { _name = value; OnPropertyChanged("Name"); }
{
private string _name = "";
Please check the following:
If you're not currently binding to name instead of _name;
Either if that is or is not the case, please fix your naming convention, because it is a source of errors, and every example you'll find follow the convention I included above.
In your XAML, you are binding "Name" property and in your code, you have created _name property. So, you need to change it to "Name" property in your code.
Just change your property as per below:
private string _name = "";
public string Name
{
get { return _name; }
set {
_name = value;
OnPropertyChanged("Name");
}
}
Try this and let me know.
I have used eventaggregator for this purpose, as we need to change the text in the text box dynamically when an event in a different view is fired. Below is the C# code of both the DropView(where we select student name from a list), and DetailsView(where we display the details). I publish events in Drop.xaml.cs and subscribe to those events in Details.xaml.cs
Drop.xaml.cs
public partial class Drop : UserControl
{
private IEventAggregator iEventAggregator;
public Drop(IEventAggregator ieventaggregator)
{
InitializeComponent();
iEventAggregator = ieventaggregator;
this.DataContext = this;
var doc = XDocument.Load("C:\\Users\\srinivasaarudra.k\\Desktop\\students.xml");
var names = doc.Descendants("Name");
foreach (var item in names)
{
droplist.Items.Add(item.Value);
}
}
public string name;
public string Naam
{
get { return name; }
set { name = value;
iEventAggregator.GetEvent<Itemselectedevent>().Publish(Naam);
}
}
public string grade;
public string Grade
{
get { return grade; }
set
{
grade = value;
iEventAggregator.GetEvent<gradeevent>().Publish(Grade);
}
}
public string dept;
public string Dept
{
get { return dept; }
set
{
dept = value;
iEventAggregator.GetEvent<deptevent>().Publish(Dept);
}
}
public static string str;
public static string Str
{
get { return str; }
set {
str = value;
}
}
private void droplist_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var sel = droplist.SelectedValue;
Str=sel.ToString();
XmlDocument doc2 = new XmlDocument();
doc2.Load("C:\\Users\\srinivasaarudra.k\\Desktop\\students.xml");
var details = doc2.DocumentElement.SelectNodes("/Students/StudentDetails");
foreach (XmlNode node in details)
{
if (node.SelectSingleNode("Name").InnerText == Str)
{
Naam = node.SelectSingleNode("Name").InnerText;
Grade = node.SelectSingleNode("Grade").InnerText;
Dept = node.SelectSingleNode("Department").InnerText;
}
}
// Details det = new Details();
Details dt = new Details(iEventAggregator);
}
}
public class Itemselectedevent:Prism.Events.PubSubEvent<string>
{
}
public class gradeevent : Prism.Events.PubSubEvent<string>
{
}
public class deptevent : Prism.Events.PubSubEvent<string>
{
}
Details.xaml.cs
public partial class Details : UserControl,INotifyPropertyChanged
{
public IEventAggregator iEventAggregator;
public event PropertyChangedEventHandler PropertyChanged;
public static string name;
public static string dept;
public static string grade;
[Bindable(true)]
public string Naam
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Naam");
}
}
[Bindable(true)]
public string Grade
{
get { return grade; }
set
{
grade = value; OnPropertyChanged("Grade");
}
}
[Bindable(true)]
public string Dept
{
get { return dept; }
set
{
dept = value;
OnPropertyChanged("Dept");
}
}
public Details(IEventAggregator eventaggregator)
{
InitializeComponent();
this.iEventAggregator = eventaggregator;
iEventAggregator.GetEvent<Itemselectedevent>().Subscribe((str) => { Naam = str; });
iEventAggregator.GetEvent<gradeevent>().Subscribe((str) => { Grade = str; });
iEventAggregator.GetEvent<deptevent>().Subscribe((str) => { Dept = str; });
this.DataContext = this;
}
protected void OnPropertyChanged(string s)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(s));
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
}

MVVM Bindings not working properly

Update
Managed to fix the selectedIndex problem. I'd forgotten to set SelectedItem as well and naturally that caused a few issues.
So at 9AM this morning we got our 24 hour assignment and I have hit a brick wall.
We're supposed to create a program that allows a supervisor to Add and delete Employees and add Working Sessions, total hours and total earnings. But I am having some problems succesfully implementing this following the MVVM-Pattern. For some reason my Bindings simply aren't working and the only Solution I can see is someone looking over my project and helping me troubleshoot it.
Here is my code - I'm very sorry about having to post the entire thing but given that I have no clue where the problem is I did not see any other options. :
EmployeeModel
[Serializable]
public class WorkSessions : ObservableCollection<WorkSessionModel>
{
public WorkSessions()
{
}
}
[Serializable]
public class WorkSessionModel : INotifyPropertyChanged
{
private DateTime _dateTime;
private string _id;
private double _hours;
public WorkSessionModel()
{
}
public DateTime DateTime
{
get { return _dateTime; }
set
{
_dateTime = value;
NotifyPropertyChanged("DateTime");
}
}
public string ID
{
get { return _id; }
set
{
_id = value;
NotifyPropertyChanged("ID");
}
}
public double Hours
{
get { return _hours; }
set
{
_hours = value;
NotifyPropertyChanged("Hours");
NotifyPropertyChanged("TotalHours");
}
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
WorkSessionModel
[Serializable]
public class WorkSessions : ObservableCollection<WorkSessionModel>
{
public WorkSessions()
{
}
}
[Serializable]
public class WorkSessionModel : INotifyPropertyChanged
{
private DateTime _dateTime;
private string _id;
private double _hours;
public WorkSessionModel()
{
}
public DateTime DateTime
{
get { return _dateTime; }
set
{
_dateTime = value;
NotifyPropertyChanged("DateTime");
}
}
public string ID
{
get { return _id; }
set
{
_id = value;
NotifyPropertyChanged("ID");
}
}
public double Hours
{
get { return _hours; }
set
{
_hours = value;
NotifyPropertyChanged("Hours");
NotifyPropertyChanged("TotalHours");
}
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
EmployeeViewModel
public class EmployeeViewModel : ViewModelBase
{
private Employees _employeesModel = new Employees();
public Employees EmployeesView = new Employees();
public ObservableCollection<WorkSessionModel> WorkSessions { get; set; }
private string _id = "0";
private string _name = "noname";
private double _wage = 0;
private int _totalhours = 0;
public string ID
{
get { return _id; }
set { _id = value; RaisePropertyChanged("ID"); }
}
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
public double Wage
{
get { return _wage; }
set
{
_wage = value;
RaisePropertyChanged("Wage");
}
}
public int TotalHours
{
get { return _totalhours; }
set
{
_totalhours = value;
RaisePropertyChanged("TotalHours");
}
}
private EmployeeModel _selectedEmployee = new EmployeeModel();
public EmployeeModel SelectedEmployee
{
get { return _selectedEmployee; }
set
{
_selectedEmployee = value;
RaisePropertyChanged("SelectedEmployee");
}
}
private int _selectedEmployeeIndex;
public int SelectedEmployeeIndex
{
get { return _selectedEmployeeIndex; }
set
{
_selectedEmployeeIndex = value;
RaisePropertyChanged("SelectedEmployeeIndex");
}
}
#region RelayCommands
// Employee Relay Commands
public RelayCommand EmployeeAddNewCommand { set; get; }
public RelayCommand EmployeeDeleteCommand { set; get; }
public RelayCommand EmployeeNextCommand { set; get; }
public RelayCommand EmployeePrevCommand { set; get; }
public RelayCommand EmployeeTotalHoursCommand { get; set; }
#endregion
public EmployeeViewModel()
{
InitCommands();
}
private void InitCommands()
{
EmployeeAddNewCommand = new RelayCommand(EmployeeAddNewExecute, EmployeeAddNewCanExecute);
EmployeeDeleteCommand = new RelayCommand(EmployeeDeleteNewExecute, EmployeeDeleteCanExecute);
EmployeeNextCommand = new RelayCommand(EmployeeNextExecute, EmployeeNextCanExecute);
EmployeePrevCommand = new RelayCommand(EmployeePrevExecute, EmployeePrevCanExecute);
//EmployeeTotalHoursCommand = new RelayCommand(EmployeeTotalHoursExecute, EmployeeTotalHoursCanExecute);
}
//private void EmployeeTotalHoursExecute()
//{
// _selectedEmployee.TotalHours();
//}
//private bool EmployeeTotalHoursCanExecute()
//{
// return true;
//}
private void EmployeeAddNewExecute()
{
EmployeeModel newEmployee = new EmployeeModel();
EmployeesView.Add(newEmployee);
_employeesModel.Add(newEmployee);
SelectedEmployee = newEmployee;
}
private bool EmployeeAddNewCanExecute()
{
return true;
}
private void EmployeeDeleteNewExecute()
{
if (MessageBox.Show("You are about delete all submissions for Employee," + SelectedEmployee.Name + "(" + SelectedEmployee.ID +")\r\nAre you sure?", "This is a Warning!", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
_employeesModel.Remove(SelectedEmployee);
EmployeesView.Remove(SelectedEmployee);
}
}
private bool EmployeeDeleteCanExecute()
{
if (SelectedEmployee != null)
return true;
else return false;
}
private void EmployeeNextExecute()
{
SelectedEmployeeIndex++;
}
private bool EmployeeNextCanExecute()
{
if (SelectedEmployeeIndex < EmployeesView.Count - 1)
return true;
return false;
}
private void EmployeePrevExecute()
{
SelectedEmployeeIndex--;
}
private bool EmployeePrevCanExecute()
{
if (SelectedEmployeeIndex > 0)
return true;
return false;
}
}
View
public partial class MainWindow : Window
{
public EmployeeViewModel EmployeeViewModel = new EmployeeViewModel();
public MainWindow()
{
InitializeComponent();
menu_employee.DataContext = EmployeeViewModel;
sp_employees.DataContext = EmployeeViewModel;
datagrid_employees.ItemsSource = EmployeeViewModel.EmployeesView;
grid_selectedEmployee.DataContext = EmployeeViewModel.SelectedEmployee;
}
}
I can see a few problems with your code:
When the SelectedIndex is updated, SelectedItem remains the same and vice versa.
It looks like your data binding is out of order:
The DataContext property cascades down to every child of a certain dependency object.
The code in the MainWindow constructor should probably be replaced by:
this.DataContext = EmployeeViewModel;
Then in XAML set the rest of the properties using Data Binding. The problem in your situation is that the DataContext of the selectedemployee is only set once. This means if you select another employee, then it will not update.
An example for your SelectedEmployee grid:
<Grid Name="grid_selectedEmployee" DataContext="{Binding SelectedEmployee,
UpdateSourceTrigger=PropertyChanged}">...</Grid>
One of the biggest things I see is you are setting properties, not binding them.
For example,
datagrid_employees.ItemsSource = EmployeeViewModel.EmployeesView;
You are telling your DataGrid that it's ItemsSource should be that specific object. You need to bind it to that value so you are telling it to point to that property instead. This will make your UI correctly reflect what's in your ViewModel
The other huge red flag I see is your ViewModel referencing something called and EmployeeView which leads me to believe your View and ViewModel too closely tied together.
Your ViewModel should contain all your business logic and code, while the View is usually XAML and simply reflects the ViewModel in a user-friendly way.
The View and the ViewModel should never directly reference each other (I have had my View reference my ViewModel in some rare occasions, but never the other way around)
For example, an EmployeesViewModel might contain
ObservableCollection<Employee> Employees
Employee SelectedEmployee
ICommand AddEmployeeCommand
ICommand DeleteEmployeeCommand
while your View (XAML) might look like this:
<StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="Add" Command="{Binding AddEmployeeCommand}" />
<Button Content="Delete" Command="{Binding DeleteEmployeeCommand}" />
</StackPanel>
<DataGrid ItemsSource="{Binding Employees}"
SelectedItem="{Binding SelectedEmployee}">
... etc
</DataGrid>
<UniformGrid DataContext="{Binding SelectedEmployee}" Columns="2" Rows="4">
<TextBlock Text="ID" />
<TextBox Text="{Binding Id}" />
... etc
</UniformGrid >
</StackPanel>
And the only thing you should be setting is the DataContext of the entire Window. Usually I overwrite App.OnStartup() to start up my application:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var view = new MainWindow();
var vm = new EmployeesViewModel;
view.DataContext = vm;
view.Show();
}
}
Although I suppose in your case this would also work:
public MainWindow()
{
InitializeComponent();
this.DataContext = new EmployeesViewModel();
}

Categories