WPF MVVM Combobox binding - c#

I have created a combo box and im binding in MVVM pattern, but my properties are not binding to the view, I'm confused with itemsource and selectvalue.
What changes can I make to view.xaml? I'm guessing the remainder of the code in my model and view model are perfect.
This is my Model
namespace screensaver.Models {
class ConfigurationModel {
public int _resolution;
private ObservableCollection < ConfigurationModel > Resolution {
get {
return Resolution;
}
set {
Resolution = value;
}
}
public ConfigurationModel() {
Resolution = new ObservableCollection < ConfigurationModel > () {
new ConfigurationModel() {
_resolution = 360 * 720
},
new ConfigurationModel() {
_resolution = 720 * 1080
},
new ConfigurationModel() {
_resolution = 1080 * 2060
}
};
}
}
}
This is my ViewModel
namespace screensaver.ViewModels {
class ConfigurationViewModel {
private ObservableCollection < ConfigurationModel > _resolution;
public ObservableCollection < ConfigurationModel > Resolution {
get {
return Resolution;
}
set {
Resolution = value;
}
}
}
}
This is my View xaml code
<Window x:Class="screensaver.Views.ConfigurationWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ViewModels="clr-namespace:screensaver.ViewModels" Title="ConfigurationWindow"
Height="1000" Width="500">
<Grid>
<Label Content="Display" HorizontalAlignment="Left" Margin="7,12,0,0" VerticalAlignment="Top" />
<ComboBox HorizontalAlignment="Left" Margin="322,14,0,0" VerticalAlignment="Top" Width="120" />
<ComboBox ItemsSource="{Binding Resolution}" SelectedItem="{Binding
Resolution, Mode=TwoWay}" DisplayMemberPath="{Binding Resolution}" HorizontalAlignment="Left" Margin="74,13,0,0" VerticalAlignment="Top" Width="120" />
<Label Content="Resolution" HorizontalAlignment="Left" Margin="250,13,0,0" VerticalAlignment="Top" />
<Button Content="Save" HorizontalAlignment="Left" Margin="80,362,0,0" VerticalAlignment="Top" Width="75" />
<Button Content="Close" HorizontalAlignment="Left" Margin="350,360,0,0" VerticalAlignment="Top" Width="75" />
<Label Content="Height" HorizontalAlignment="Left" Margin="72,178,0,0" VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="140,181,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
<Label Content="Width" HorizontalAlignment="Left" Margin="290,175,0,0" VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="346,179,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
<Label Content="Top" HorizontalAlignment="Left" Margin="76,253,0,0" VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="140,255,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
<Label Content="Left" HorizontalAlignment="Left" Margin="292,250,0,0" VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="349,252,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
</Grid>
</Window>

There are some problems with your code.
First fix your property Resolution in ViewModel to prevent a StackOverflowException. Use your field _resolution in get and set.
private ObservableCollection < ConfigurationModel > Resolution {
get {
return _resolution;
}
set {
_resolution = value;
}
}
Similar problem in your Model. Here you can use an auto-property
private ObservableCollection<ConfigurationModel> Resolution
{
get;
set;
}
Maybe you should also exchange the ObservableCollection by a List<>. But this is not necessary. The field _resolution can be removed and the type of Resolution poperty changed to ObservableCollection< string >.
private ObservableCollection<string> Resolution
{
get;
set;
}
Your constructor can then be changed to
public ConfigurationModel()
{
Resolution = new ObservableCollection<string>() {
"360 * 720",
"720 * 1080",
"1080 * 2060"
};
}
There is also missing the link from Model to ViewModel. Something like that:
private readonly ConfigurationModel _model;
public ConfigurationViewModel()
{
_model = new ConfigurationModel();
}
And then you have to use it, so you have to change your property
public ObservableCollection<string> Resolution
{
get
{
return _model.Resolution;
}
set
{
_model.Resolution = value;
}
}
Therefore you have to change the modifier in the Model from private to public.
public ObservableCollection<string> Resolution
{
get;
set;
}
Now you can remove the field _resolution from ViewModel.
DisplayMemberPath have to be removed from the View. And you have to set the DataContext properly.
<Window.DataContext>
<ViewModels:ConfigurationViewModel />
</Window.DataContext>
So far you have that result:
The SelectedItem in the View have to bind to another property in the ViewModel.
public string SelectedResolution { get; set; }
SelectedItem="{Binding SelectedResolution, Mode=TwoWay}"
This should be a good starting point to go further on. You can change the string in the ObservableCollection to an own type with more properties. Then you need to set the DisplayMemberPath again.
Here is the final code.
Model:
using System.Collections.ObjectModel;
namespace screensaver.Models
{
class ConfigurationModel
{
public ObservableCollection<string> Resolution
{
get;
set;
}
public ConfigurationModel()
{
Resolution = new ObservableCollection<string>() {
"360 * 720",
"720 * 1080",
"1080 * 2060"
};
}
}
}
ViewModel:
using screensaver.Models;
using System.Collections.ObjectModel;
namespace screensaver.ViewModels
{
class ConfigurationViewModel
{
private readonly ConfigurationModel _model;
public ConfigurationViewModel()
{
_model = new ConfigurationModel();
}
public ObservableCollection<string> Resolution
{
get { return _model.Resolution; }
set { _model.Resolution = value; }
}
public string SelectedResolution { get; set; }
}
}
View:
<Window x:Class="screensaver.Views.ConfigurationWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ViewModels="clr-namespace:screensaver.ViewModels" Title="ConfigurationWindow"
Height="1000" Width="500">
<Window.DataContext>
<ViewModels:ConfigurationViewModel />
</Window.DataContext>
<Grid>
<Label Content="Display" HorizontalAlignment="Left" Margin="7,12,0,0" VerticalAlignment="Top" />
<ComboBox HorizontalAlignment="Left" Margin="322,14,0,0" VerticalAlignment="Top" Width="120" />
<ComboBox ItemsSource="{Binding Resolution}" SelectedItem="{Binding SelectedResolution, Mode=TwoWay}" HorizontalAlignment="Left" Margin="74,13,0,0" VerticalAlignment="Top" Width="120" />
<Label Content="Resolution" HorizontalAlignment="Left" Margin="250,13,0,0" VerticalAlignment="Top" />
<Button Content="Save" HorizontalAlignment="Left" Margin="80,362,0,0" VerticalAlignment="Top" Width="75" />
<Button Content="Close" HorizontalAlignment="Left" Margin="350,360,0,0" VerticalAlignment="Top" Width="75" />
<Label Content="Height" HorizontalAlignment="Left" Margin="72,178,0,0" VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="140,181,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
<Label Content="Width" HorizontalAlignment="Left" Margin="290,175,0,0" VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="346,179,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
<Label Content="Top" HorizontalAlignment="Left" Margin="76,253,0,0" VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="140,255,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
<Label Content="Left" HorizontalAlignment="Left" Margin="292,250,0,0" VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="349,252,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
</Grid>
</Window>

Related

WPF How to visit each child of a UniformGrid

The UserControl is composed of two labels and one Textbox.Some relative codes are below
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
DataContext = this;
}
public string Title { get; set; }
public string Company {get; set; }
public TextBox TrueText;
private void Input_Loaded(object sender, RoutedEventArgs e)
{
this.TrueText = sender as TextBox;
}
}
xaml
<Viewbox >
<Grid HorizontalAlignment="Left" VerticalAlignment="Center">
<Label Content="{Binding Title}" HorizontalAlignment="Left" Height="20" VerticalAlignment="Center" Padding="0,0,0,0" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Width="180"/>
<TextBox Margin="180,0,0,0" Name="Input" Loaded="Input_Loaded" Controls:TextBoxHelper.Watermark="待输入" Controls:TextBoxHelper.ClearTextButton="True" Padding="0,0,0,0" VerticalContentAlignment="Center" MinHeight="0" HorizontalAlignment="Left" VerticalAlignment="Center" Width="120" Height="18"/>
<Label Content="{Binding Company}" HorizontalAlignment="Left" Height="18" Margin="300,1,0,0" VerticalAlignment="Top" Width="50" Padding="0,0,0,0" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
</Grid>
</Viewbox>
Then I want to get the Input in TextBox of each UserControl.But I can't get the children of the UniformGrid.
I have tried to use GetChildObject, but in this way I can't access his related properties
This is my wrong codeyour text
IEnumerable<UserControl1> list = (IEnumerable<UserControl1>)Grid1.GetChildObjects();
int i = 1;
double[] num = { 0 };
foreach (var u in list)
{
i++;
num[i] = Convert.ToDouble(u.TrueText.Text);
}
Any solution will be truly appreciated

INotifyPropertyChanged is not refreshing my listview in WPF MVVM entity

I have one action in my view model to add record in to entity frame work.I have one action to display the records in the view like this :
private void FillProspects()
{
var q = (from a in ctx2.Prospects// 'ctx' is the object of entity
select a).ToList();
this.Prospects = q; // 'Porspects' is a collection of entity class this I have bound with my List view in my view
}
This will be called in construction of my view model.as a result the list view in my view will be showing the records .
I have one add record action in my view model..I have created properties in my view model corresponding to properties generated in the entity class for example:
private String _FirstName;
public String FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
}
}
And my add record action in the view model is :
public void Add1()
{
newprospect = new Prospect();
newprospect.ID = Guid.NewGuid();
newprospect.FirstName = FirstName;
newprospect.LastName = LastName;
newprospect.Address = Address;
newprospect.State = State;
newprospect.City = City;
newprospect.ZIP = ZIP;
prospect = newprospect;
ctx2.AddToProspects(prospect);
FillProspects();
//RaisePropertyChanged("Prospects");
}
I have inherited the : INotifyPropertyChanged and imported it's
using System.Windows.Input;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string property) { PropertyChanged(this, new PropertyChangedEventArgs(property)); }
But my notification is not refreshing my view Listview records after adding record .so I just call the fill records method 'FillProspects' in the addrecord action..Is this right way of doing MVVM .Why my Listview is not getting refreshed after add record action where I am missing?I have tried with
RaisePropertyChanged("Prospects");in the Add record action...but it is not refreshing .So I just called fill method action again
My complete view model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Input;
using System.Collections.ObjectModel;
namespace Wpfentity3
{
public class frmProspects_VM : INotifyPropertyChanged
{
TestsEntities ctx2 = new TestsEntities();
public ObservableCollection<Prospect> prospects { get; set; }
//This is the collection where records - er, entities - returned by a query are stored;
//Prospect is the generated class that defines a record - er,
//an entity as well as the query for that table.
private CommandMap _Commands;
public CommandMap Commands { get { return _Commands; } }
Prospect newprospect;
//This holds a new prospect that is created and then added to the prospects collection
private Prospect _prospect;
public Prospect prospect {
get
{
return _prospect;
}
set
{
_prospect = value;
RaisePropertyChanged("prospect");
}
}
//prospect is the object that holds the current record from the Prospects table.
//MainWindow controls are bound to this object
public frmProspects_VM()
{
//FillProspects();
ctx2 = new TestsEntities();
//This instantiates the EntityManager class ;
prospects = new ObservableCollection<Prospect>();
//This instantiates the prospects collection of Prospect records - er, entities;
_Commands = new CommandMap();
_Commands.AddCommand("Add", x => Add1());
}
private ObservableCollection<Prospect> _prospects;
public ObservableCollection<Prospect> Prospects
{
get
{
return _prospects;
}
set
{
_prospects = value;
RaisePropertyChanged("Prospects");
}
}
private String _FirstName;
public String FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
}
}
private String _LastName;
public String LastName
{
get
{
return _LastName;
}
set
{
_LastName = value;
}
}
private String _Address;
public String Address
{
get
{
return _Address;
}
set
{
_Address = value;
}
}
private String _State;
public String State
{
get
{
return _State;
}
set
{
_State = value;
}
}
private String _City;
public String City
{
get
{
return _City;
}
set
{
_City = value;
}
}
private String _ZIP;
public String ZIP
{
get
{
return _ZIP;
}
set
{
_ZIP = value;
}
}
public void Add1()
{
newprospect = new Prospect();
newprospect.ID = Guid.NewGuid();
newprospect.FirstName = FirstName;
newprospect.LastName = LastName;
newprospect.Address = Address;
newprospect.State = State;
newprospect.City = City;
newprospect.ZIP = ZIP;
prospect = newprospect;
ctx2.AddToProspects(prospect);
Prospects.Add(newprospect);
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string property) { PropertyChanged(this, new PropertyChangedEventArgs(property)); }
}
}
My view xamal:
<Window x:Class="Wpfentity3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStartupLocation="CenterScreen"
Title="Prospects"
Height="482" Width="500" MaxWidth="500" MaxHeight="600"
xmlns:cusns="clr-namespace:Wpfentity3">
<StackPanel Height="290" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" >
<Label
Content="Prospects"
BorderBrush="Blue" BorderThickness="1"
HorizontalAlignment="Left" VerticalAlignment="Top"
FontSize="24" FontFamily="Comic Sans MS"
Padding="13,3,13,9" Margin="5"
Foreground="Purple" Background="LemonChiffon" />
<Label
Content="{Binding Path=label}" Foreground="Red" FontSize="14"
HorizontalAlignment="Right" VerticalAlignment="Center"
Height="auto" Margin="180,0,10,0" />
</StackPanel>
<Grid
HorizontalAlignment="Left" VerticalAlignment="Top"
Height="120" Width="475" >
<Grid.RowDefinitions>
<RowDefinition Height="25*" />
<RowDefinition Height="25*" />
<RowDefinition Height="25*" />
<RowDefinition Height="25*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="135*" />
<ColumnDefinition Width="45*" />
<ColumnDefinition Width="32*" />
<ColumnDefinition Width="57*" />
<ColumnDefinition Width="118*" />
</Grid.ColumnDefinitions>
<Label
Content="First name"
Grid.Row="0" Grid.Column="0" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtFirstName"
Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Path=FirstName}"
Width="130" />
<Label
Content="Last name"
Grid.Row="1" Grid.Column="0" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtLastName"
Grid.Row="1" Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding LastName}"
Width="130" />
<Label
Content="Address"
Grid.Row="2" Grid.Column="0" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtAddress"
Grid.Row="2" Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Address}"
Width="300" Grid.ColumnSpan="5" />
<Label
Content="City"
Grid.Row="3" Grid.Column="0" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtCity"
Grid.Row="3" Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding City}"
Width="130" />
<Label
Content="State"
Grid.Row="3" Grid.Column="2" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtState"
Grid.Row="3" Grid.Column="3" Width="30" MaxLength="2" CharacterCasing="Upper" Text="{Binding State}"
HorizontalAlignment="Left" VerticalAlignment="Center" />
<Label
Content="ZIP code"
Grid.Row="3" Grid.Column="4" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtZIP"
Grid.Row="3" Grid.Column="5" MaxLength="10"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding ZIP}"
Width="90" />
</Grid>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Button Name="btnFind"
Content="_Find"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnAdd"
Content="_Add" Command="{Binding Commands.Add}"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnEdit"
Content="_Edit"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnDelete"
Content="_Delete"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnSave"
Content="_Save"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnCancel"
Content="_Cancel"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnClose"
Content="Cl_ose"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0"
/>
</StackPanel>
<StackPanel Height="34" Margin="10">
<Grid Margin="10">
<ListView Name="lvprospects" ItemsSource="{Binding Prospects}" Margin="0,0,0,-200">
<ListView.View>
<GridView>
<GridViewColumn Header="FirstName" Width="120" DisplayMemberBinding="{Binding FirstName}" />
<GridViewColumn Header="LastName" Width="50" DisplayMemberBinding="{Binding LastName}" />
<GridViewColumn Header="Address" Width="50" DisplayMemberBinding="{Binding Address}" />
<GridViewColumn Header="City" Width="50" DisplayMemberBinding="{Binding City}" />
<GridViewColumn Header="State" Width="50" DisplayMemberBinding="{Binding State}" />
<GridViewColumn Header="ZIP" Width="50" DisplayMemberBinding="{Binding ZIP}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</StackPanel>
</StackPanel>
Change the type of the Prospects property from List<Prospect> to ObservableCollection<Prospect>:
private ObservableCollection<Prospect> _prospects = new ObservableCollection<Prospect>();
public ObservableCollection<Prospect> Prospects
{
get
{
return _prospects;
}
set
{
_prospects = value;
RaisePropertyChanged("Prospects");
}
}
And add the new Prospect object to this collection as well in your Add1 method:
public void Add1()
{
newprospect = new Prospect();
newprospect.ID = Guid.NewGuid();
newprospect.FirstName = FirstName;
newprospect.LastName = LastName;
newprospect.Address = Address;
newprospect.State = State;
newprospect.City = City;
newprospect.ZIP = ZIP;
prospect = newprospect;
ctx2.AddToProspects(prospect);
Prospects.Add(newprospect);
}
Just adding it to the DbContext doesn't affect the ListView.
It is fine to add the new item to the DB and then retrieve again the collection with the same refresh method FillProspects:
what you're doing is basically correct.
If you're going to bind a view to a collection in your ViewModel, I suggest using an ObservableCollection.
The ObservableCollection implements INotifyCollectionChanged, it notifies the view when elements are added or removed.
With this you should not need your "FillProspects" method and your "RaisePropertyChanged("Prospects")".
If you want more information I suggest posting how you bind in your XAML and also how you construct your "Prospects" object (we don't even know what type it is, I just assume it isn't an ObservableCollection).
EDIT :
you bind your ListView to "Prospects", but in your ViewModel, I see that "Prospects" is of type "List", it needs to be "ObservableCollection". I see that you have an ObservableCollection named "prospects", but you don't use it anywhere. Could this be the issue ?

C# Master Detail View - Reverting unsaved changes

I'm creating CRUD application in C# with Caliburn.Micro and I have some Master Detail View that looks like that:
What i want to achieve is, when i make some changes(for example i change capacity from 47 to 50), and then select the other place, let's say Place 4 and select Place 5 again my capacity will be 47, not 50 like it is now.
I was thinking about OneTime binding, and manually firing binding to the viewmodel then, but viewModel should not have been aware of the view, so that seems like a bad idea. My code below.
XAML:
<DataGrid x:Name="Places"
Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"
Width="290"
HorizontalAlignment="Left"
CanUserReorderColumns="False" CanUserResizeColumns="False" IsReadOnly="True"
AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="False" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTextColumn Header="Place" Binding="{Binding Name, Mode=OneTime}" MinWidth="150"
Width="SizeToCells" />
</DataGrid.Columns>
</DataGrid>
<Grid Grid.Column="0" Grid.Row="2"
Width="290" Height="210"
HorizontalAlignment="Left" VerticalAlignment="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110" />
<ColumnDefinition Width="180" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="60" />
<RowDefinition Height="30" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Label Content="ID"
Grid.Column="0" Grid.Row="0" VerticalAlignment="Top" />
<Label Content="Place*"
Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" />
<Label Content="Address*"
Grid.Column="0" Grid.Row="2" VerticalAlignment="Top" />
<Label Content="Capacity*"
Grid.Column="0" Grid.Row="3" VerticalAlignment="Top" />
<Label Content="Comments"
Grid.Column="0" Grid.Row="4" VerticalAlignment="Top" />
<TextBox x:Name="SelectedPlace_Id"
Grid.Column="1" Grid.Row="0" VerticalAlignment="Top"
IsEnabled="False" />
<TextBox x:Name="SelectedPlace_Name"
Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" />
<TextBox x:Name="SelectedPlace_Address"
Grid.Column="1" Grid.Row="2"
Height="55" VerticalAlignment="Top"
TextWrapping="Wrap" />
<TextBox x:Name="SelectedPlace_Capacity"
Grid.Column="1" Grid.Row="3" VerticalAlignment="Top" />
<TextBox x:Name="SelectedPlace_Comments"
Grid.Column="1" Grid.Row="4" Height="55"
VerticalAlignment="Top"
TextWrapping="Wrap" />
</Grid>
<Button x:Name="DeletePlace" Content="Delete"
Grid.Column="0" Grid.Row="3"
Width="100" Height="30" Margin="0 0 110 0"
HorizontalAlignment="Right" VerticalAlignment="Top" />
<Button x:Name="SavePlace" Content="Save"
Grid.Column="0" Grid.Row="3"
Width="100" Height="30" Margin="0 0 5 0"
HorizontalAlignment="Right" VerticalAlignment="Top" />
ViewModel:
class PlacesTabViewModel : TabViewModel
{
#region Fields
private BindableCollection<Place> _places;
private Place _selectedPlace;
#endregion
#region Methods
public PlacesTabViewModel()
{
using (var ctx = new DbCtx(App.DatabasePath))
{
_places = new BindableCollection<Place>(ctx.Places.OrderBy(p => p.Name));
}
}
public override string ToString()
{
return "Places";
}
#endregion
#region Events
public bool CanDeletePlace => _selectedPlace != null;
public bool CanSavePlace => (_selectedPlace != null) && _selectedPlace.IsValid();
public void DeletePlace()
{
using (var ctx = new DbCtx(App.DatabasePath))
{
try
{
ctx.Entry(SelectedPlace).State = EntityState.Deleted;
ctx.SaveChanges();
}
catch (DbUpdateException)
{
//TODO: Error
return;
}
Places.Remove(SelectedPlace);
NotifyOfPropertyChange(nameof(Places));
NotifyOfPropertyChange(() => CanDeletePlace);
NotifyOfPropertyChange(() => CanSavePlace);
}
}
public void SavePlace()
{
using (var ctx = new DbCtx(App.DatabasePath))
{
try
{
ctx.Places.Attach(_selectedPlace);
ctx.Entry(_selectedPlace).State = EntityState.Modified;
ctx.SaveChanges();
}
catch
{
//TODO: Error
}
NotifyOfPropertyChange(nameof(Places));
}
}
#endregion
#region Properties
public BindableCollection<Place> Places
{
get { return _places; }
set
{
if (value != _places)
{
_places = value;
NotifyOfPropertyChange(nameof(Places));
}
}
}
public Place SelectedPlace
{
get { return _selectedPlace; }
set
{
if (value != _selectedPlace)
{
_selectedPlace = value;
if (_selectedPlace != null)
{
_selectedPlace.PropertyChanged += (sender, args) =>
{
NotifyOfPropertyChange(() => CanSavePlace);
};
}
NotifyOfPropertyChange(nameof(SelectedPlace));
NotifyOfPropertyChange(() => CanDeletePlace);
NotifyOfPropertyChange(() => CanSavePlace);
}
}
}
#endregion
}
ViewModel for the MainWindow
class MainWindowViewModel : PropertyChangedBase
{
#region Fields
private BindableCollection<TabViewModel> _tabs = new BindableCollection<TabViewModel>();
#endregion
public MainWindowViewModel()
{
_tabs.Add(new PlacesTabViewModel());
}
#region Properties
public BindableCollection<TabViewModel> Tabs
{
get { return _tabs; }
set
{
if (value != _tabs)
{
_tabs = value;
NotifyOfPropertyChange(nameof(Tabs));
}
}
}
#endregion
}
WPF doesn't know Normal properties. You either have to make it a dependency property, or in your case, your VM has to implement INotifyPropertyChanged. when the value changes it will automatically updated.
May be you didn't applied INotifyPropertyChanged property for SelectedPlace_Capacity.
I think that this is the issue.

WPF enable buttons group

In first column i have list of groups ("First","Second"). In second column i have 5 button's. I want to enable or disable group of button's after choosing their group in first column. How to do this in MVVM pattern?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Data();
}
}
public class Data
{
public List<string> Items { get; set; }
public Data()
{
Items = new List<string>();
Items.Add("First");
Items.Add("Second");
}
}
Xaml:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding Items}" Grid.Column="0">
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding .}"></Label>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="First" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="21,24,0,0" VerticalAlignment="Top" Width="76" IsEnabled="False"/>
<Button Content="Second" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="102,48,0,0" VerticalAlignment="Top" Width="76" IsEnabled="True"/>
<Button Content="First" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="33,83,0,0" VerticalAlignment="Top" Width="76" IsEnabled="False"/>
<Button Content="Second" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="126,93,0,0" VerticalAlignment="Top" Width="76" IsEnabled="True" RenderTransformOrigin="1.088,-0.075"/>
<Button Content="Second" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="93,186,0,0" VerticalAlignment="Top" Width="76" IsEnabled="True"/>
</Grid>
Create your VM classes like:
public class Data:INotifyPropertyChanged
{
public ObservableCollection<MyRecord> Items
{
get{
return _items;
}
set{
_items=value;
OnProperyChanged("Items")
}
}
public Data()
{
Items = new ObservableCollection<MyRecord>()
{
new MyRecord(){Title:"First",IsEnable:false}),
new MyRecord(){Title:"Second",IsEnable:false})
};
}
//---------------------------------------------------------------
public event PropertyChangedEventHandler PropertyChanged;
private void OnProperyChanged(string propertyName)
{
if (PropertyChanged != null)
{
var handler= PropertyChanged ;
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MyRecord:INotifyPropertyChanged
{
private int _title;
private bool _isEnable;
public int Title
{
get
{
return _title;
}
set
{
_title= value;
OnProperyChanged("Title")
}
}
public bool IsEnable
{
get
{
return _isEnable;
}
set
{
_isEnable= value;
OnProperyChanged("IsEnable")
}
}
//---------------------------------------------------------------
public event PropertyChangedEventHandler PropertyChanged;
private void OnProperyChanged(string propertyName)
{
if (PropertyChanged != null)
{
var handler= PropertyChanged ;
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Now in your Xaml bind the IsEnabled property of each Button to appropriate property...
You can write the following code with BooleanToVisibilityConverter:
//First add BooleanToVisibilityConverter to the window resources
// When you know Items[0] is FIRST use some code like this>>
IsEnabled="{Binding Items[0].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Sample:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding Items}" Grid.Column="0">
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding .}"></Label>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="First"
IsEnabled="{Binding Items[0].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="21,24,0,0" VerticalAlignment="Top" Width="76"/>
<Button Content="Second"
IsEnabled="{Binding Items[1].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="102,48,0,0" VerticalAlignment="Top" Width="76"/>
<Button Content="First"
IsEnabled="{Binding Items[0].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="33,83,0,0" VerticalAlignment="Top" Width="76"/>
<Button Content="Second"
IsEnabled="{Binding Items[1].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="126,93,0,0" VerticalAlignment="Top" Width="76" RenderTransformOrigin="1.088,-0.075"/>
<Button Content="Second"
IsEnabled="{Binding Items[1].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="93,186,0,0" VerticalAlignment="Top" Width="76"/>
</Grid>
OK, every things is good until this step. Now if you make IsEnable property of each item to TRUE, then the buttons must be Enabled And conversely. To perform it you can:
Write a Command in your Data class and make a binding between each List
item and the command.
Use ListView.SelectionChanged event to make IsEnable property of the Clicked item to TRUE. Note: Now, the type of each item in the ListView is MyRecord.
The best solution to your problem is to use a IValueConverter, in this example I created a convert named GroupToBooleanConverter receiving the value of the selected item in the first column by the parameter value and the button group by parameter 'parameter ', the code converter is below:
public class GroupToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var selectedGroup = value as string;
var buttonGroup = (string)parameter;
return buttonGroup.Equals(selectedGroup);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Now in its XAML you must reference the namespace of your turn, in my example the namespace convert is namespaceOfConverter, and must be imported to convert through it, is as follows:
xmlns:converters="clr-namespace:namespaceOfConverter"
Place the attribute up on your Window tag in your XAML. Now you must reference the convert, putting it in the Window resources:
<Window.Resources>
<converters:GroupToBooleanConverter x:Key="GroupToBoolean" />
</Window.Resources>
I called your ListView of lsvGroups:
<ListView ItemsSource="{Binding Items}" x:Name="lsvGroups" Grid.Column="0">
....
Now just use the converter in your buttons, performing binding in the property IsEnabled:
IsEnabled="{Binding SelectedItem, ElementName=lsvGroups,Converter={StaticResource GroupToBoolean},ConverterParameter=First}"
OBs: In the place of First you put the name of group associate with button.

Data is not displayed on the View

I have made a wpf application for implementing the MVVM architecture. I can see the forma but the data is not loaded in the form please help is needed. I am using Visual studio 2012.
Below is the code:
Model:- User.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace TestApplication.Model
{
public class User : INotifyPropertyChanged
{
private int userId;
private string firstName;
private string lastName;
private string city;
private string state;
private string country;
public int UserId
{
get
{
return userId;
}
set
{
userId = value;
OnPropertyChanged("UserId");
}
}
public string FirstName
{
get
{
return firstName;
}
set
{
firstName = value;
OnPropertyChanged("FirstName");
}
}
public string LastName
{
get
{
return lastName;
}
set
{
lastName = value;
OnPropertyChanged("LastName");
}
}
public string City
{
get
{
return city;
}
set
{
city = value;
OnPropertyChanged("City");
}
}
public string State
{
get
{
return state;
}
set
{
state = value;
OnPropertyChanged("State");
}
}
public string Country
{
get
{
return country;
}
set
{
country = value;
OnPropertyChanged("Country");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
View :- MainPage.xml
<Window x:Class="TestApplication.View.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestApplication" Height="485" Width="525">
<Grid Margin="0,0,0,20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView Name="UserGrid" Grid.Row="1" Margin="4,178,12,13" ItemsSource="{Binding Users}" >
<ListView.View>
<GridView x:Name="grdTest">
<GridViewColumn Header="UserId" DisplayMemberBinding="{Binding UserId}" Width="50"/>
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="80" />
<GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}" Width="100" />
<GridViewColumn Header="City" DisplayMemberBinding="{Binding City}" Width="80" />
<GridViewColumn Header="State" DisplayMemberBinding="{Binding State}" Width="80" />
<GridViewColumn Header="Country" DisplayMemberBinding="{Binding Country}" Width="100" />
</GridView>
</ListView.View>
</ListView>
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtUserId" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=UserGrid,Path=SelectedItem.UserId}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtFirstName" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=UserGrid,Path=SelectedItem.FirstName}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,62,0,0" Name="txtLastName" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=UserGrid,Path=SelectedItem.LastName}" />
<Label Content="UserId" Grid.Row="1" HorizontalAlignment="Left" Margin="12,12,0,274" Name="label1" />
<Label Content="Last Name" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,60,0,0" Name="label2" VerticalAlignment="Top" />
<Label Content="First Name" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,35,0,0" Name="label3" VerticalAlignment="Top" />
<Button Content="Update" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="310,40,0,0" Name="btnUpdate"
VerticalAlignment="Top" Width="141"
Command="{Binding Path=UpdateCommad}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,143,0,0" x:Name="txtCity" VerticalAlignment="Top" Width="178" Text="{Binding SelectedItem.City, ElementName=UserGrid}" />
<Label Content="Country" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,141,0,0" x:Name="label2_Copy" VerticalAlignment="Top" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,88,0,0" x:Name="txtCountry" VerticalAlignment="Top" Width="178" Text="{Binding SelectedItem.Country, ElementName=UserGrid}" />
<Label Content="City" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,86,0,0" x:Name="label2_Copy1" VerticalAlignment="Top" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,115,0,0" x:Name="txtSTate" VerticalAlignment="Top" Width="178" Text="{Binding SelectedItem.State, ElementName=UserGrid}" />
<Label Content="State" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,113,0,0" x:Name="label2_Copy2" VerticalAlignment="Top" />
</Grid>
</Window>
View Model : UserViewMOdel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using TestApplication.Model;
using System.Windows.Input;
namespace TestApplication.ViewModel
{
class UserViewModel
{
private IList<User> _UsersList;
public UserViewModel()
{
_UsersList = new List<User>
{
new User{UserId = 1,FirstName="Raj",LastName="Beniwal",City="Delhi",State="DEL",Country="INDIA"},
new User{UserId=2,FirstName="Mark",LastName="henry",City="New York", State="NY", Country="USA"},
new User{UserId=3,FirstName="Mahesh",LastName="Chand",City="Philadelphia", State="PHL", Country="USA"},
new User{UserId=4,FirstName="Vikash",LastName="Nanda",City="Noida", State="UP", Country="INDIA"},
new User{UserId=5,FirstName="Harsh",LastName="Kumar",City="Ghaziabad", State="UP", Country="INDIA"},
new User{UserId=6,FirstName="Reetesh",LastName="Tomar",City="Mumbai", State="MP", Country="INDIA"},
new User{UserId=7,FirstName="Deven",LastName="Verma",City="Palwal", State="HP", Country="INDIA"},
new User{UserId=8,FirstName="Ravi",LastName="Taneja",City="Delhi", State="DEL", Country="INDIA"}
};
}
public IList<User> Users
{
get { return _UsersList; }
set { _UsersList = value; }
}
private ICommand mUpdater;
public ICommand UpdateCommand
{
get
{
if (mUpdater == null)
mUpdater = new Updater();
return mUpdater;
}
set
{
mUpdater = value;
}
}
private class Updater : ICommand
{
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
}
#endregion
}
}
}
You need to initialize the DataContext of your View. You can do this in the ctor of your MainPage.
I assume here that the UserViewModel is the ViewModel for your MainPage.
public MainPage() {
InitializeComponents();
this.DataContext = new UserViewModel();
}

Categories