How to know that property was changed from View - silverlight

My silverlight project uses MVVM.For examlpe, I have textbox, that binded to ViewModel property. Textbox content can change from View or ViewModel. I need know when content changed from View. How can I implement this accordingly MVVM?

If your viewmodel has INotifyPropertyChanged/INotifyPropertyChanging implemented then you can hook into it. That works for me.

if you use bindings, you get the information in your setter.
Here is a little example:
XAML:
<TextBox Text="{Binding MyProperty, Mode=TwoWay}" />
C# of your ViewModel:
private string myProperty = "Test";
public String MyProperty
{
get { return myProperty; }
set
{
Debug.WriteLine("Property set");
myProperty = value;
NotifyPropertyChanged("MyProperty");
}
}
Each time, you change the text and the TextBox looses the focus, the setter get called.
If you want to get the setter called each time you hit a key, have a look here. This is a little bit of a quick and dirty solution for triggering the binding ;) A better way would be to write an Behaviour for this.
Hope this helps!
BR,
TJ

Related

WPF and data binding

I have a WPF app where i want to control IsEnabled property of several textboxes in code by setting just one bool. So i decide to add databinding for textboxes IsEnabled property.
Here is the source object definition:
<Window.Resources>
<src:QuestionControlsState x:Key="QuestionContorlsState" IsEnabled="True"/>
</Window.Resources>
Where 'QuestionControlsState' simple class with only one public property 'IsEnabled'
Then i bind some of textboxes:
<TextBox Name="textBoxQuestion"
IsEnabled="{Binding Path=IsEnabled, Source={StaticResource QuestionContorlsState}}">
At this point it works fine, when i change IsEnabled attribute in Window.Resources section databinding works.
But i want to control it from code, so i get source object:
QuestionControlsState _questionControlsState = (QuestionControlsState)this.FindResource("QuestionContorlsState");
And now when i try to set _questionControlsState.IsEnabled, textbox state not change and there is now warnings in output.
Without seeing your code, I'm guessing your QuestionControlsState class isn't implementing INotifyPropertyChanged.
Modify it like this:
public class QuestionControlsState : INotifyPropertyChanged
{
private bool isEnabled = true;
public bool IsEnabled
{
get { return isEnabled; }
set
{
isEnabled = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("IsEnabled"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
This will trigger a PropertyChanged event whenever you change the IsEnabled property, notifying the view it needs to refresh.
Of course, if you're using the MVVM pattern, the correct way of doing this is binding all textboxes to a boolean IsEnabled property in the ViewModel and not by trying to find the static resource in codebehind... Then, a simple IsEnabled = false in the VM will disable all textboxes (without the need of a staticresource)
Please use the MVVM pattern to passing data to tha XAML view and to encapsulate the view logic and to make the view logic testable.
With MVVM its very easy to create a observable property which can be bound to the IsEnabled properties of your controls. You only have to change the Property with a Command to true or false to enable or disable the property.
Thank you guys, Blachshma you was right i forgot to implement INotifyPropertyChanged interface on my custom class and now it works like it should. Thank you! I think about MVVM pattern and it looks cool but i just started with WPF and want to learn basics.
You can try to change StaticResource to DynamicResource.
You can find information here

How can I realize SelectionChanged in MVVM ListBox Silverlight

The ListBox control does not implement a Command property. I have to attach some functionality to the SelectionChanged event. Somebody knows how can I do it? Please help me
I prefer using a binding to the SelectedItem and implementing any functionality in the setting of the binding property.
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" />
...
public class ViewModel
{
public IEnumerable<Item> Items { get; set; }
private Item selectedItem;
public Item SelectedItem
{
get { return selectedItem; }
set
{
if (selectedItem == value)
return;
selectedItem = value;
// Do logic on selection change.
}
}
}
This is the way where You can Reach the Selection changed events in Your MVVM Application
First Of all i tell you that Command Property only work in Button now we have to Explicitly
binding that property in our Selection Changed event like List box or combo box
in Your XMAL file
<ListBox Name="MyListBox" ItemsSource="{Binding ListItems}" Height="150" Width="150" Margin="281,32,-31,118">
<Local:Interaction.Triggers>
<Local:EventTrigger EventName="SelectionChanged">
<Local:InvokeCommandAction Command="{Binding MyCommand}" CommandParameter="{Binding ElementName=MyListBox,Path=SelectedItem}"/>
</Local:EventTrigger>
</Local:Interaction.Triggers>
</ListBox>
for this you have to add dll Syatem.Windows.Interactivity
now u have to add references in your xaml file namespace like
xmlns:Local="clr-namespace:System.Windows.Interactivityassembly=System.Windows.Interactivity"
in your ViewModel Class you have to define your Command in Con structure
public ViewModel123()
{
MyCommand = new RelayCommand<string>(TestMethod);
}
now create the TestMethod method which can handle the selection changed event
private void TestMethod(string parameter)
{
MessageBox.Show(parameter);
}
i hope this may help u.
Basically you have a few options:
Use the property SelectedItem of ListBox to bind to a property in the backend (ie in view model) and perform logic in the setter as described by Cameron MacFarland.
Use a third party library that has a generic event to command behavior like in the link posted by Pedro Lamas.
If you don't want to use third party libraries or writing logic inside property setter is somehow unacceptable you can create your own behavior for ListBox control. It would subscribe to control's SelectionChanged event and execute a command (the command could be a dependency property exposed by the behavior).
Think this post from Laurent Bugnion will help you solve the problem:
http://geekswithblogs.net/lbugnion/archive/2010/05/19/handling-datagrid.selecteditems-in-an-mvvm-friendly-manner.aspx
The post above mentions the DataGrid but I do think it will work with the ListBox too!
Best regards and Happy New Year!! :)
I would suggest using RelayCommand. Either use the MVVM Light Toolkit or just use the RelayCommand and CommandManager classes from Josh Smith's implementations. I personally use just the two classes, so I don't need the entire toolkit.
While this will definitely work, there might be an easier way depending on what you are doing. It might just be easier to bind an object to the SelectedValue of the ListBox and listen for that value to change.

DataBinding Text Property of UserControl to ObservableCollection does not update

I have created a UserControl, which is to display a converted string value based on the contents of a bound ObservableCollection. Everything works when the application loads; my IValueConverter is called and produces the correct string result, which is displayed correctly in my UserControl. However if the ObservableCollection contents change, my control is not updated.
Also, before I created this control, I had the same behaviour, but binding the Content property of a regular Button control, and this also worked correctly and updated as expected.
Any ideas what I am missing to get the same thing with my UserControl?
The control property looks like;
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MyUserControl));
public string Text
{
get { return GetValue(TextProperty) as string; }
set { SetValue(TextProperty, value);
}
The relevant section in the UserControl XAML (which displays the converted string value) is;
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:MyUserControl}}, Path=Text}" />
And the control is created in a separate Window like so;
<CoreControls:MyUserControl
Name="myControl"
Text="{Binding Path=ObservableCollectionInstance, Converter={StaticResource MyValueConverter}, Mode=OneWay}" />
I would use ElementName instead of RelativeSource in your binding, since you have named your user control. Also, you are trying to bind a collection to a <Textbox>. a <Textbox> is designed to display a single item. this is probably why its not working. ObservableCollection fires CollectionChanged events, not PropertyChanged. Even if it did respond, you are still going to have problems because ObservableCollection does not notify when an item contained in it has property changes--only when items are added/removed etc (think, the collection itself changes). If this is the behavior you want, you are going to have to write some code.
EDIT
after your comments, it sounds to me like even though you set it to OneWay binding mode, its acting like OneTime binding mode.
I would try this to help you debug it:
add this xmlns:
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"
and then, in your binding add this:
diagnostics:PresentationTraceSources.TraceLevel=High
here is an article on debugging bindings.
the other thing you could do is set breakpoints in your converter. see if its actually updating when you add/remove things to your collection. I would be willing to bet that its bc the ObservableCollection is NOT firing PropertyChanged events and that the initial update occurs because its not based on an update event.
ObservableCollection notifies only in case if items get added or removed. It is used to observe a collection. They are more suited for content controls. Read about it here. You are talking about observing a property, which needs INotifyPropertyChanged. Posting more code might help, like how are you changing the value of the collection.
Thanks for the tips guys.
I managed to work out a solution; I can handle the CollectionChanged event on the ObservableCollection and then explicitly update the target with something like;
BindingExpression exp = myControl.GetBindingExpression(MyUserControl.TextProperty);
if (null != exp) exp.UpdateTarget();
As noted, most likely, binding on the Text property is only listening to PropertyChanged events, not NotifyCollectionChanged events, but this solution does the trick.

WPF User Control Binding Issue?

I have this:
public MyView: UserControl
{
public IList<Person> PersonList { get; set; }
public MyView()
{
//code
}
public void Display(MyData myData)
{
DataContext=myData;
}
//code
}
The XAML for this includes a ComboBox :
ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=PersonList}"
For some reason this does not work and the combo box does not get populated ( however, If I use the code-behind and I say comboBox.ItemsSource = PersonList then the combo box does got populated ).
Any ideas ?
Regards,
MadSeb
Your property is set to private, and are you sure that you are setting the DataContext.
* EDIT *
Based on the change you made above, you're setting your datacontext incorrectly. Your "PersonList" is anIList<> on your MyView class, but you're setting your data context to something else.
Try adding items to PersonList within MyView and setting this.DataContext = this; Also, as suggested, switch your IList<> to an ObservableCollection<>.
I would also highly suggest reading up on the Model View ViewModel (MVVM) approach. It will help out a lot. Josh Smith has a lot of good articles about the MVVM approach (and has written a good book about it too).
Here's a link to his blog. His book is linked there, as well.
I suspect it's because you're not firing any property-changed events. If you don't notify your UI when the property's value is first set, the binding won't update. Look into the INotifyPropertyChanged interface and implement it in your class.
Similarly, if your IList property isn't an ObservableCollection or doesn't implement INotifyCollectionChanged, then when you add items to the list the databound UI won't reflect this.
I believe your binding statement is the problem.
"{Binding RelativeSource={RelativeSource Self}, Path=PersonList}" is looking for a "PersonList" on the combobox itself.
Are you seeing any binding errors in the output window?
Ideally you'd want to bind to a property in your DataContext (MyData)

MVVM: Binding to ListBox.SelectedItem isn't being updated?

How do I bind a view model property to the ListBox.SelectedItem property?
I have created a simple MVVM demo to try to figure this one out. My view model has these properties:
private ObservableCollection<DisneyCharacter> p_DisneyCharacters;
public ObservableCollection<DisneyCharacter> DisneyCharacters
{
get { return p_DisneyCharacters; }
set
{
p_DisneyCharacters = value;
base.FirePropertyChangedEvent("DisneyCharacters");
}
}
private DisneyCharacter p_SelectedItem;
public DisneyCharacter SelectedItem
{
get { return p_SelectedItem; }
set
{
p_SelectedItem = value;
base.FirePropertyChangedEvent("SelectedItem");
}
}
I want to bind the SelectedItem property to the item selected in the list box. Here is the XAML for the list box:
<ListBox ItemTemplate="{StaticResource MasterTemplate}"
ItemsSource="{Binding Path=DisneyCharacters}"
SelectedItem="{Binding Path=Selectedtem, Mode=TwoWay}"
HorizontalAlignment="Stretch" />
Here is my problem: The view model SelectedItem property isn't being updated when I change the selection in the list box.
I did a test where I temporarily replaced the view model SelectedItem property with a SelectedIndex property, and I bound that to the ListBox.SelectedIndex property. That property updated fine--it's just the SelectedItem property that I can't get to work.
So, how do I fix the SelectedItem binding? Thanks for your help.
Well, there it is, big as life. In the XAML I was binding to a view model property called:
Selectedtem
^^
Unfortunately, the actual name is SelectedItem. So this code actually works--I solved the problem early this afternoon and then spent the rest of the afternoon and all evening scouring the web, before I noticed the spelling error.
My wife told me at 3:00 this afternoon, "You know, it's going to turn out to be something small." And so it did--a missing letter I. Well, at least I can go to bed now.

Resources