I am using MVVM and want to enable a button on text change of datepicker control..
XAML Code:
Binding on DatePicker
SelectedDate="{Binding InactiveDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayDate="{Binding InactiveDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
Binding on Button:
<Button Margin="10" Command="{Binding SubmitCommand}"
View Model Code:
I am using a DelegateCommand for button click
View Model Delegate Initialization
SubmitCommand = new DelegateCommand(OnSubmitRequested, AllowSubmit, Controller);
The AllowSubmit implementation
private bool AllowSubmit()
{
return InactiveDate != null;
}
InactiveDate Property implementation
public DateTime? InactiveDate
{
get
{
return _inactiveDate;
}
set
{
_inactiveDate = value;
SubmitCommand.RaiseCanExecuteChanged();
PropertyChanged(this, new PropertyChangedEventArgs("InactiveDate"));
}
}
SubmitCommand.RaiseCanExecuteChanged() should enable the button once I enter any character on DateTimePicker but it is not happening.
Selected Date property does not work properly. I might be a bit late now, but you can use CurrentDateTimeText property of RadDatePicker
Related
I've got a really simple UserControl I'm trying to create that contains a list of US states. I am trying to expose the selected state via a "SelectedState" property. However, I'm having trouble trying to get this binding to fire once it's hooked up in another UserControl / form.
The XAML for the user control looks like this:
<UserControl x:Class="Sample.Desktop.UserControls.StateDropdown"
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:Sample.Desktop.UserControls"
mc:Ignorable="d"
Width="170" Height="28"
d:DesignHeight="28" d:DesignWidth="170">
<ComboBox x:Name="cboState"
ItemsSource="{Binding StateList, RelativeSource={RelativeSource AncestorType=UserControl}}"
SelectedValue="{Binding SelectedState, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=UserControl}}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Abbreviation}"></Label>
<Label> - </Label>
<Label Content="{Binding Name}"></Label>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
In the code-behind, I have this code:
public static readonly DependencyProperty SelectedStateProperty = DependencyProperty.Register("SelectedState",
typeof(USState),
typeof(StateDropdown),
new UIPropertyMetadata(null,
new PropertyChangedCallback(OnSelectedStateChanged),
new CoerceValueCallback(OnCoerceSelectedState)));
private static object OnCoerceSelectedState(DependencyObject o, object value)
{
StateDropdown stateDropdown = o as StateDropdown;
if (stateDropdown != null)
return stateDropdown.OnCoerceSelectedState((USState)value);
else
return value;
}
private static void OnSelectedStateChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
StateDropdown stateDropdown = o as StateDropdown;
if (stateDropdown != null)
stateDropdown.OnSelectedStateChanged((USState)e.OldValue, (USState)e.NewValue);
}
protected virtual USState OnCoerceSelectedState(USState value)
{
// TODO: Keep the proposed value within the desired range.
return value;
}
protected virtual void OnSelectedStateChanged(USState oldValue, USState newValue)
{
// TODO: Add your property changed side-effects. Descendants can override as well.
}
public USState SelectedState
{
// IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
get
{
return (USState)GetValue(SelectedStateProperty);
}
set
{
SetValue(SelectedStateProperty, value);
}
}
I wasn't able to get the SelectedValue bound property of SelectedState to fire, so I ended up hooking up the SelectionChanged event.
private void cboState_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems?.Count > 0)
{
SelectedState = (USState)e.AddedItems[0];
}
}
In my other user control, I have this in the XAML:
<uc:StateDropdown Margin="10,0,0,0" SelectedState="{Binding SelectedState}" ></uc:StateDropdown>
And the ViewModel (I'm using Caliburn Micro), I have this property:
protected USState _selectedState;
public USState SelectedState
{
get { return _selectedState; }
set
{
_selectedState = value;
NotifyOfPropertyChange(() => SelectedState);
}
}
The combo is populated as expected. However, SelectedState is never fired/updated when I change the selection.
I had also previously tried using SelectedItem instead of SelectedValue, with the same results.
I'm sure I'm missing something obvious, but I'm having trouble seeing where I went wrong.
EDIT: Here's what fixed the binding.
I removed the SelectionChanged event. Then I modified my "hosting page" usercontrol to set TwoWay binding:
<uc:StateDropdown Margin="10,0,0,0" SelectedState="{Binding SelectedState, Mode=TwoWay}" ></uc:StateDropdown>
As soon as I added that, SelectedState started being updated when I changed the ComboBox value.
The only things I see, is this line :
SelectedValue="{Binding SelectedState, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=UserControl}}"
You don't need it, because of the SelectionChanged event. And it can cause the problem.
Also I would bind the SelectedState of the UserControl using a TwoWay binding.
Hope that will help you.
I have successfully passed the following Enum to a Combobox using the following:
public enum Color
{
Blue,
Green,
Yellow
}
public Color _color { get; set; }
public Type Colors
{
get { return typeof(Color); }
}
In the view I have the following:
<ComboBox ItemsSource="{Binding Colors, Converter={StaticResource enumConverter}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding }" FontSize="14"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
This lets me pic a color in the box. What I want to do is to bind the chosen color to a property that's part of my viewmodel. I am very new to converters so I might be missing something.
You can bind the SelectedItem of the ComboBox to a property in your view model. The type of that property must match the type of the items generated by the enumConverter.
You can bind Combobox's SelectedItem to the property. I rename the Property to SelectedColor in the ViewModel. The PropertyChanged event is raised in the setter, so when you update the property, for example, from another method inside ViewModel, the view is notified and updated with the new value.
private Color _selectedColor;
public Color SelectedColor
{
get { return _selectedColor; }
set
{
_selectedColor = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("SelectedColor"));
}
}
}
And in the XAML
<ComboBox ItemsSource="{Binding Colors, Converter={StaticResource enumConverter}}"
SelectedItem="{Binding SelectedColor}">
...
I have a wpf (.Net 4.5) datagrid. I am using the MVVM pattern for my application with the MVVM-Light framework.
I have a datagrid that is bound to an observable collection of "Tracking" objects called TrackingCollection. The datagrid selectedItem is bound to a "SelectedTracking" property in the viewModel.
<DataGrid Grid.Column="1" Grid.Row="3" Grid.ColumnSpan="3" MinHeight="300"
ItemsSource="{Binding TrackingCollection}"
CanUserAddRows="False" CanUserDeleteRows="False"
SelectionMode="Single" SelectedItem="{Binding SelectedTracking, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
RowDetailsTemplate="{StaticResource FTC_TrackingFullDetailTemplate}">
</DataGrid>
I have a comboBox in one column that is bound to an "idAction" property of the SelectedTracking object. When the user changes the selection of this comboBox, I want to assign the values of two other combo boxes in two other columns of the datagrid. These other columns are not bound to properties of the view model, rather they are bound directly to the properties of the SelectedTracking object. These properties of the SelectedTracking object are iSource_Type and iDestination_Type.
Here is the column definition for iSourceType:
<DataGridTemplateColumn Header="SOURCE" SortMemberPath="tracking_source.chrSource" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Style="{StaticResource FTC_DetailComboBox}" Margin="0" Padding="3"
ItemsSource="{Binding DataContext.TrackingSources, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
SelectedValuePath="idSource"
DisplayMemberPath="chrSource"
SelectedValue="{Binding iSource_Type, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
So when I assign these (iSource_Type, iDestination_Type) values in the ViewModel code (in a selectionChanged function of the first "Action" comboBox) the values are updated on the object itself. But the change is not reflected back to the UI's comboboxes bound to these properties.
What I tried:
First:
I have an implementation of INotifyPropertyCHanged with a function called RaisePropertyChanged. THis is provided through the MVVM_Light framework. SO i tried to use the following:
RaisePropertyChanged("iDestination_Type")
RaisePropertyChanged("iSource_Type")
RaisePropertyChanged("SelectedTracking")
RaisePropertyChanged("SelectedTracking.iDestination_Type")
RaisePropertyChanged("SelectedTracking.iSource_Type")
But these do not work.
Second:
I also tried to create properties in the viewmodel that bound to the SelectedTracking object. But this just caused all the tracking objects to get the same values.
Question:
Can INotifyPropertyChanged work on properties that are not a part of the viewmodel, but are properties of objects found in the view model. If so, what syntax do I need in the INotifyPropertyChanged event?
Additional INformation:
The MVVM-Light implementation of INotifyPropertyChanged (RaisePropertyChanged()) does not accept an empty string that would normaly update all UI elements. So is there a way I can override the Implementation of INotifyPropertyCHanged in just one CLass?
If I understand your problem correctly you would like a way to notify your ViewModel of changes to your Model.
If so you can implement INotifyPropertyChanged in your model and subscribe to the model objects PropertyChanged event in your ViewModel. Here you can raise the property changed notification on your ViewModel properties.
A simple example to demonstrate the concept:
Model:
public class Tracking : INotifyPropertyChanged
{
private string _isourcetype;
private string _idestinationtype;
public string SourceType
{
get { return _isourcetype; }
set
{
_isourcetype = value;
OnPropertyChanged("SourceType");
}
}
public string DestinationType
{
get { return _idestinationtype; }
set
{
_idestinationtype = value;
OnPropertyChanged("DestinationType");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
ViewModel:
public class TrackingViewModel : ViewModelBase
{
private Tracking _selectedTracking;
public string DestinationType
{
get { return _selectedTracking.DestinationType; }
}
public string SourceType
{
get { return _selectedTracking.SourceType; }
}
public Tracking SelectedTracking
{
get { return _selectedTracking; }
set
{
_selectedTracking = value;
RaisePropertyChanged("SelectedTracking");
}
}
public TrackingViewModel()
{
_selectedTracking = new Tracking();
_selectedTracking.PropertyChanged += SelectedTracking_PropertyChanged;
}
void SelectedTracking_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "SourceType":
RaisePropertyChanged("SourceType");
break;
case "DestinationType":
RaisePropertyChanged("DestinationType");
break;
}
}
}
Below is the XAML snippet for my combo-box in a datagrid.
<data:DataGridTemplateColumn Header="Entry Mode">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=EntryModeCombo,Mode=TwoWay}" DisplayMemberPath="Name" SelectedValuePath="Id" SelectedValue="{Binding Path=selectedEntryMode,Mode=TwoWay}" ></ComboBox>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
Entrymode is an entity in the system and the Id and Name properties of this entity are used to set the DisplayMemberPath and SelectedValuePath of the combo.
public class A
{
private ObservableCollection<EntryMode> _EntryModeCombo;
public ObservableCollection<EntryMode> EntryModeCombo
{
get { return _EntryModeCombo; }
set
{
_EntryModeCombo = value;
RaisePropertyChanged("EntryModeCombo");
}
}
private string _selectedEntryMode;
public string selectedEntryMode
{
get { return _selectedEntryMode; }
set
{
_selectedEntryMode = value;
RaisePropertyChanged("selectedEntryMode");
}
}
}
In my viewModel, I am making an observable collection of the class A, and using that to bind a grid. All works well in the ADD mode, but in the edit mode, when I try to set the selected value of the combobox in the grid, it does not work. The population of the combo-box happens, but it remains unselected. Not sure why the selectedEntryMode property is getting set, but not affecting the combo selection in the grid.
Any suggestions will be appreciated.Thanks.
SelectedValue can only be used for getting value. not setting. use SelectedItem insted
I am new to MVVM, and also fairly new to WPF. As a matter of fact I started programming just a few months ago. MVVM is really dng my head in with the binding concept, and I have been trying for days now to just simply make an application that allows you to select an item from a listbx, and when you click on the add button the selected item should be saved in a new list. The second listbox displays the latest items added, and you can select an item and delete it by using another button. ususally I would go for the click event and decorate my codebehind with pretty little methods, but I really want to learn how to do all this by using bindings and no codebehind.
I would be extremly happy for any help, and please remember that I am new to this and I really want to keep it as simple as possible :)
with kind regards Daniela
<WrapPanel HorizontalAlignment="Center" Margin=" 10">
<ListBox x:Name="Firstbox"
Width="100"
ItemsSource="{Binding FoodList}"
DisplayMemberPath="Name" >
</ListBox>
<Button Margin="10 >Select</Button>
<ListBox Width="100"></ListBox>
private List _foodList;
public List<FoodItem> FoodList
{
get { return _foodList; }
set { _foodList = value; }
}
private List<FoodItem> _newFoodList;
public List<FoodItem> NewFoodList
{
get { return _newFoodList; }
set { _newFoodList = value; }
}
public MainViewModel()
{
InitializeCommands();
GetFood();
}
private void GetFood()
{
FoodList = new List<FoodItem>()
{
new FoodItem() {Name="Applepie"},
new FoodItem() {Name="Scones"}
};
}
first, you need to replace the Lists with ObservableCollections, so that the UI can detect when new items are added.
Add a SelectedItem property to your ViewModel:
private FoodItem _selectedItem;
public FoodItem SelectedItem
{
get { return _selectedItem;}
set
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
bind the SelectedItem property of the 1st ListBox to this property:
<ListBox Width=" 100" x:Name="Firstbox"
ItemsSource="{Binding FoodList}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedItem}" />
bind your 2nd ListBox to the NewFoodList property
create a command in your ViewModel:
private DelegateCommand _addItemCommand;
public ICommand AddItemCommand
{
get
{
if (_addItemCommand == null)
{
_addItemCommand = new DelegateCommand(AddItem);
}
return _addItemCommand;
}
}
void AddItem()
{
if (SelectedItem != null)
NewFoodList.Add(SelectedItem);
}
And finally, bind the button's Command property to the AddItemCommand property:
<Button Margin="10" Command="{Binding AddItemCommand}" >Select</Button>