Please help, I was trying to do this small example.
My aim is to when I keep the checkbox ticked the app should show the the Ip address of the Host I enter. But The checkbox IsChecked property is never updated in the view model, Even it is been changed in the UI
My View `
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.00" Color="LavenderBlush" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
<StackPanel Grid.Row="0" Margin="150,30,69,236" Grid.ColumnSpan="2">
<TextBox x:Name="inputBox" Text="{Binding TxtHostName, Mode=TwoWay}" Foreground="Azure" Background="YellowGreen" VerticalAlignment="Bottom" Height="45"/>
</StackPanel>
<Button Command="{Binding StartCommand }" Content="Get IP" HorizontalAlignment="Left" Margin="257,89,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="0.013,-0.273"/>
<TextBlock Text="{Binding IpAddress}" Background="BlueViolet" Margin="150,153,69,104" Grid.ColumnSpan="2" />
<Button Content="Close" Command="{Binding CloseCommand}" HorizontalAlignment="Left" Margin="257,250,0,0" VerticalAlignment="Top" Width="75"/>
<CheckBox Content="CheckBox" IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left" Margin="150,111,0,0" VerticalAlignment="Top"/>
</Grid>
`
My ViewModel:
public class ViewModel:INotifyPropertyChanged
{
#region INPC
public void RaisePropertyChanged(string propName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private string txtHostName;
public string TxtHostName
{
get { return txtHostName; }
set { txtHostName = value;
RaisePropertyChanged("TxtHostName");
}
}
private string ipAddress;
public string IpAddress
{
get { return ipAddress; }
set { ipAddress = value;
RaisePropertyChanged("IpAddress");
}
}
private bool checkbox;
public bool CheckBox
{
get { return checkbox; }
set { checkbox = value;
RaisePropertyChanged("IsSelected");
}
}
public event EventHandler RequestClose;
protected void OnRequestClose()
{
if (RequestClose != null)
RequestClose(this, EventArgs.Empty);
}
private RelayCommand _StartCommand;
public ICommand StartCommand
{
get
{
if (this._StartCommand == null)
this._StartCommand = new RelayCommand(StartClick);
return this._StartCommand;
}
}
private RelayCommand _CloseCommand;
public ICommand CloseCommand
{
get
{
if(this._CloseCommand==null)
this._CloseCommand=new RelayCommand(CloseClick);
return this._CloseCommand;
}
}
private void CloseClick(object obj)
{
OnRequestClose();
}
private void StartClick(object obj)
{
if (checkbox)
{
string HostName = TxtHostName;
IPAddress[] ipaddress = Dns.GetHostAddresses(HostName);
foreach (IPAddress ipaddr in ipaddress)
{
IpAddress = ipaddr.ToString();
}
}
else
{
IpAddress = "Please tick the checkbox";
}
}
}
}
The RealyCommand is as it should be.
The CheckBox Property value never changes weather I change it in the UI or not.
Your raising your property changed event against IsSelected, but your bindable property is called Checkbox, rename Checkbox to IsSelected and update your private variable to something like isSelected.
In this case Id rename the variable to IsChecked or ComboBoxIsChecked.
I'm not sure if there is a copy-and-paste error but your View Model property is called Checkbox while you are raising the property changed event using the label IsSelected.
This and the error in the binding might be your problem. Based on your View Model the binding should be:-
<CheckBox Content="CheckBox" IsChecked="{Binding Checkbox, Mode=TwoWay}" HorizontalAlignment="Left" Margin="150,111,0,0" VerticalAlignment="Top"/>
Update: Recommendation if you are using C# 5.0 or above
To avoid typo's when creating setters and raising IPropertyNotifyChange events I would recommend using the CallerMemberName attribute as follows:-
public void RaisePropertyChanged([CallerMemberName] string propName = "")
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
Then your setter in your example becomes:-
private bool checkbox;
public bool CheckBox
{
get { return checkbox; }
set { checkbox = value;
RaisePropertyChanged();
}
}
Meaning as you refactor your View Model then the compiler will insert the name of the calling property to ensure the label in the INotifyProertyChanged event matches your property name without you having to remember to manually update it yourself.
Related
I have a ListBox control with TypeUsers.When I select some record in Listbox and update Name in TextBox the Name property/textbox return always null. Never take value from TextBox, always null ?
Image description here
This is my code
<ListBox x:Name="LstTypeUsers"
Grid.Row="0" Grid.Column="4"
Width="220" Height="120"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ItemsSource="{Binding TypeUsers}"
DisplayMemberPath="Name">
</ListBox>
<TextBox
Grid.Row="0" Grid.Column="2"
x:Name="txtName"
HorizontalAlignment="Left" Height="23"
TextWrapping="Wrap"
VerticalAlignment="Top" Width="170"
Text="{Binding ElementName=LstTypeUsers, Path=SelectedItem.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Validation.ErrorTemplate="{x:Null}"/>
<Button
Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="100" Height="30"
Command="{Binding UpdateTypeUserCmd}"
Grid.ColumnSpan="3" Margin="20,90,0,0">
<StackPanel Orientation="Horizontal">
<Image Source="/Images/Save.png" />
<TextBlock Width="55" Height="18" ><Run Text=" "/><Run Text="Update"/></TextBlock>
</StackPanel>
</Button>
EDIT
// Model class
public class UserType: INotifyPropertyChanged
{
[Key]
private int usertypeId;
public int UserTypeId
{
get
{
return this.usertypeId;
}
set
{
this.usertypeId = value;
OnPropertyChanged("UserTypeId");
}
}
[MaxLength(200)]
private string name;
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
OnPropertyChanged("Name");
}
}
[Required]
private bool status;
public bool Status
{
get
{
return this.status;
}
set
{
this.status = value;
OnPropertyChanged("Status");
}
}
public virtual ObservableCollection<User> User { get; private set; }
public UserType()
{
this.User = new ObservableCollection<User>();
}
}
// ViewModelBase class
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// UserTypeViewModel
public class UserTypeViewModel
private UserType _userType;
private ObservableCollection<UserType> _UserTypeList;
// Constructor
public UserTypeViewModel()
{
_userType = new UserType();
_UserTypeList = new ObservableCollection<UserType>(GetUserTypeAll());
}
public ObservableCollection<TypeUsers> TypeUsers
{
get
{
return _UserTypeList;
}
set
{
_UserTypeList = value;
//OnPropertyChanged("TypeUsers");
}
}
public string Name
{
get
{
return _userType.Name;
}
set
{
_userType.Name = value;
//OnPropertyChanged("Name");
}
}
Thank you.
Implement INotifyPropertyChanged interface in UserType class.
You're binding directly to the WPF control (ListBox) and not the ViewModel. I suggest you add a property in your ViewModel that will bind to the TextBox.Text property, once the data changes or the user had changed the value in the TextBox, then the data will update and be reflected in the UI.
Also, if I remember correctly, at launch, the SelectedItem property of the ListBox is null, so there might be a problem there too, but I'm not certain about that...
I have resolved my problem. I have also implemented INotifyPropertyChanged interface in Model class. I'm new in WPF MVVM and I read that this interface is implemented only in the ViewModel for connection with View. Now I have implemented in both classes and everything works great.
Thanks Everyone.
My WPF window binds directly to an Entity Framework data context (CollectionViewSource). Users begin editing immediately once a record is found. The moment the form is dirty I'd like to disable the Add button and enable the Save and Undo buttons. Is there a simple way to do this using binding or an event?
I'm not using MVVM. I use Entity Framework database first and the EF designer. I'm hoping to avoid adding code for every field. The database is quite large.
You can do this without events if you'd like. And you can leverage the power of DataBinding without going so far as MVVM. The example below demonstrates, in a very simple way, how you can accomplish this. If your entity classes don't already have an IsDirty property (it has been a while since I've used database-first EF), you could add the property with a partial class.
XAML:
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Center" Text="Name:" Margin="10"/>
<TextBox x:Name="NameTextBox" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="10" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
<StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Save" HorizontalAlignment="Right" Margin="5" IsEnabled="{Binding IsDirty}" />
<Button Content="Cancel" HorizontalAlignment="Right" Margin="5" IsEnabled="{Binding IsDirty}" Click="Cancel_Click"/>
<Button Content="Add" HorizontalAlignment="Right" Margin="5" IsEnabled="{Binding IsClean}"/>
</StackPanel>
</Grid>
</Window>
A test Entity class:
public class Entity : INotifyPropertyChanged
{
private string _name;
private bool _isDirty = false;
public string Name
{
get { return _name; }
set
{
if(!IsDirty)
IsDirty = (value != _name);
_name = value;
RaisePropertyChanged("Name");
}
}
public bool IsDirty
{
get{ return _isDirty; }
set{
_isDirty = value;
RaisePropertyChanged("IsDirty");
RaisePropertyChanged("IsClean");
}
}
public bool IsClean
{
get { return !_isDirty; }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
And the code behind for the window:
namespace Test
{
public partial class EditTesting : Window
{
private Entity _myEntity;
public EditTesting()
{
InitializeComponent();
_myEntity = new Entity();
this.DataContext = _myEntity;
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
_myEntity.Name = string.Empty;
_myEntity.IsDirty = false;
}
}
}
I have list of checkboxes on a window specifying some items to be ordered. I need to first disable the Order button when the windows loads and enable it after selecting/check some items(checkboxes) and vice versa. I have bind the IsChecked property of the checkbox.
Edit Import from OP comment:-
I have only one checkbox in the ItemsControl. and I have bind the ItemsControl's ItemsSource to List. that way we can show multiple checkboxes as per the items in the List.
Here is the code:
<ItemsControl ItemsSource="{Binding FavoriteItems}" Margin="80,0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel>
<Grid>
<CheckBox IsChecked="{Binding IsHouseholdSelected}" Content="{Binding SubCategoryName}" Grid.ColumnSpan="1" FontFamily="Calibri" FontWeight="Bold" />
</Grid>
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
Below is a sample code that could help you out. Basically, the key here is I had the Items in the list implicitly notify its parent ViewModel's Command object to raise the CanExecuteChanged event every time the IsChecked property changes. (Also, I'm using "DelegateCommand" here, which is just the same as "RelayCommand").
ViewModels:
public class ViewModel : INotifyPropertyChanged
{
public DelegateCommand MyCommand { get; set; }
private ObservableCollection<ItemViewModel> items = new ObservableCollection<ItemViewModel>();
public ObservableCollection<Item> Items
{
get { return this.items; }
}
public ViewModel()
{
this.items.Add(new ItemViewModel(this) { IsChecked = false, Text = "Item 1" });
this.items.Add(new ItemViewModel(this) { IsChecked = false, Text = "Item 2" });
this.items.Add(new ItemViewModel(this) { IsChecked = false, Text = "Item 3" });
this.MyCommand = new DelegateCommand(this.CanExecute, this.Execute);
}
public void Execute(object parameter)
{
MessageBox.Show("Executed");
}
public bool CanExecute(object parameter)
{
return (this.items.Count == this.items.Count((x) => x.IsChecked));
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
#endregion
}
public class ItemViewModel
{
private ViewModel parent;
private bool isChecked;
public string Text { get; set; }
public bool IsChecked
{
get { return this.isChecked; }
set
{
this.isChecked = value;
if (this.parent.MyCommand != null)
this.parent.MyCommand.OnCanExecuteChanged(null);
}
}
public Item(ViewModel parent)
{
this.parent = parent;
}
}
View:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<DockPanel>
<Button DockPanel.Dock="Bottom" Command="{Binding MyCommand}">Test</Button>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Text}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
</Window>
Bind a command to the button and implement the CanExecute method to check the status of the checkboxes and either enable or disable the button and use the Execute method to invoke the functionality that you want on the button.
MVVM RelayCommand
CanExecute on MSDN
EDIT: Here is some source code of how to implement a RelayCommand. The RelayCommand class can be found at the first link provided above. I'm assuming that you know how to hook up the DataContext to the ViewModel implementation.
<StackPanel>
<CheckBox Name="MyCheckBox" Content="Some CheckBox"
IsChecked="{Binding MyCheckBoxChecked}"/>
<Button Content="Click me" Command="{Binding MyCommand}"/>
</StackPanel>
public class OrderViewModel
{
private RelayCommand MyRelayCommand;
public OrderViewModel()
{
MyRelayCommand = new RelayCommand(Execute, CanExecute);
MyCheckBoxChecked = false;
}
public RelayCommand MyCommand
{
get { return MyRelayCommand; }
}
public bool MyCheckBoxChecked { get; set; }
private bool CanExecute(object o)
{
// Here I'm just checking the property we've bound to but you can put
// anything in here that will return a bool, including a check of any/all
// of the checkboxes you may need to check
return MyCheckBoxChecked;
}
private void Execute(object o)
{
Console.WriteLine(#"Executing ...");
}
}
i have customized ListBox declared in XAML:
<ListBox x:Name="uicMDSQonfServer">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
Margin="0,5,0,5">
<CheckBox IsChecked="{Binding RelativeSource={TemplatedParent},
Path=Activated}" />
<ContentPresenter Content="{Binding RelativeSource={TemplatedParent},
Path=Content}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I need to dsiplay and interop with generic List, where T is:
public class QonfServer: QonfBase, INotifyPropertyChanged
{
private string ip;
private bool activated;
public string Ip {
get { return ip; }
}
public bool Activated
{
get { return activated; }
set
{
if (activated == value)
return;
activated = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Activated"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
QonfBase is pretty simple Base class:
public class QonfBase
{
private int id;
public int ID { get; set; }
}
When i turn Activated property programmatically, checkbox do not change state. Debug: PropertyChanged = null. Anybody know, what is incorrect?
One obvious problem meets the eye: TemplatedParent is for use with ControlTemplates. Since you're using a DataTemplate, this should work:
<CheckBox IsChecked="{Binding Activated}" />
<ContentPresenter Content="{Binding Content}"/>
I didn't notice any problems with the C#.
I have a ComboBox which is has an ItemTemplate applied on it and is bind to a List of entity return using linq. I'm using mvvm. It is bind to it successfully but when I set the selected value of it from code at runtime to show the selected value coming from db it doesn't select it. For reference here is my ComboBox xaml.
<DataTemplate x:Key="ManufacturerDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image x:Name="imgManufacturer" Width="25" Height="25"
Source="{Binding Path=ManufacturerImage}" Grid.Column="0"/>
<TextBlock x:Name="txtManufacturer" Grid.Column="1" HorizontalAlignment="Left"
VerticalAlignment="Center" Text="{Binding Path=ManufacturerName}"
Tag="{Binding Path=ManufacturerID}"/>
</Grid>
</DataTemplate>
<ComboBox x:Name="cboManufacturer"
SelectionChanged="cboManufacturer_SelectionChanged"
ItemsSource = "{Binding Path=CurrentManufacturers}"
SelectedValue="{Binding Path=SelectedManufacturer}"
Grid.Column="3" Grid.Row="2" Margin="20,9.25,68,7.75"
ItemTemplate="{StaticResource ManufacturerDataTemplate}" TabIndex="6"/>
Here is my part from code behind from viewModel.
List<tblManufacturer> currentManufacturers
= new List<tblManufacturer>();
tblManufacturer selectedManufacturer = null;
public List<tblManufacturer> CurrentManufacturers
{
get
{
return currentManufacturers;
}
set
{
currentManufacturers = value;
NotifyPropertyChanged("CurrentManufacturers");
}
}
public tblManufacturer SelectedManufacturer
{
get
{
return selectedManufacturer;
}
set
{
selectedManufacturer = currentManufacturers.Where(mm => mm.ManufacturerID == Convert.ToInt32(selectedDevice.tblManufacturer.EntityKey.EntityKeyValues[0].Value)).First();
NotifyPropertyChanged("SelectedManufacturer");
}
}
Here is the sample code snippet:
Xaml for ComboBox:
<ComboBox ItemsSource="{Binding ManufacturerList}" DisplayMemberPath="Name" SelectedValuePath="ID"
SelectedItem="{Binding SelectedManufacturer}"/>
ViewModel code :
public class Manufacturer
{
public int ID { get; set; }
public string Name { get; set; }
}
private List<Manufacturer> _manufactuerlist;
private Manufacturer _selectedManufacturer;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public Manufacturer SelectedManufacturer
{
get
{
return _selectedManufacturer;
}
set
{
_selectedManufacturer = value;
NotifyPropertyChanged("SelectedManufacturer");
}
}
public List<Manufacturer> ManufacturerList
{
get
{
return _manufactuerlist;
}
set
{
_manufactuerlist = value;
NotifyPropertyChanged("ManufacturerList");
}
}
And finally Set the Selected Manufacturer in your view model like this:
SelectedManufacturer = _manufactuerlist.Find(m => m.ID == 2);