WPF MVVM getting the textbox data to the ViewModel - wpf

I have read many questions on this and so far I've not been able to find the answer on this apparently simple issue.
I have a view model, in which is a property. In my XAML I have a TextBox with a binding to that property.
But the property never seems to change.
Here's the textbox:
<TextBox Grid.Row="1"
Grid.Column="0"
Margin="4"
Text="{Binding CharNameFromTB}" />
And the relevant code behind for the ViewModel:
private String _charNameFromTB;
String CharNameFromTB
{
get { return _charNameFromTB; }
set
{
if (!string.Equals(this._charNameFromTB, value))
{
this._charNameFromTB = value;
RaisePropertyChanged("CharNameFromTB");
}
}
}
I have put a break point on the if statement in the setter, but it never triggers. Have I missed something obvious out? I tried setting the binding mode to twoway but that didn't change anything.
It's driving me a little mad. Any help would be appreciated!

You should make the property public in order to be able to bind to it:
private String _charNameFromTB;
public String CharNameFromTB
{
get { return _charNameFromTB; }
set
{
this._charNameFromTB = value;
RaisePropertyChanged("CharNameFromTB");
}
}
Also make sure that you have set the DataContext of the TextBox or any of its parent elements to an instance of your view model class where the CharNameFromTB property is defined.
Also note that by default, the source property is set when the TextBox loses focus.
If you want to update the source property on each keystroke you should set the UpdateSourceTrigger property of the Binding to PropertyChanged:
<TextBox Grid.Row="1"
Grid.Column="0"
Margin="4"
Text="{Binding CharNameFromTB, UpdateSourceTrigger=PropertyChanged}" />

Related

Bind user control dependency properties in MVVM style Windows Phone app

I'm having some issues with binding some custom controls in a Windows Phone app right now. Usually this is never an issue but apparently my mind can't comprehend this today.
So I'm doing an MVVM style setup which is good. I have my page with a view and also a viewmodel. Now on a WebClient callback I assign the dataContext of my view to the list of models in my ViewModel, nice and simple thus far...now in my view I created a ListBox with a custom control in the datatemplate which is basically a cell in the list. I once again set my user controls dataContext to binding, and binding all the models values to the regular UI elements works no problem.
Here's a sample:
<Grid Grid.Column="0">
<Image Source="{Binding SmallPath}" VerticalAlignment="Top"/>
</Grid>
<Grid Grid.Column="1">
<StackPanel Margin="12,0,0,0">
<TextBlock x:Name="MemberId_TextBlock" Text="{Binding MemberId}" FontSize="28"
Margin="0,-8,0,0"
Foreground="{StaticResource PhoneForegroundBrush}"/>
<StackPanel Orientation="Horizontal" Margin="0,-11,0,0">
<TextBlock Text="{Binding DaysReported}" FontSize="42"
Margin="0,0,0,0"
Foreground="{StaticResource PhoneAccentBrush}"/>
<TextBlock Text="days" FontSize="24"
Margin="3,19,0,0"
Foreground="{StaticResource PhoneSubtleBrush}"/>
</StackPanel>
</StackPanel>
</Grid>
That's in my user control, and here's the the view where the usercontrol is housed:
<Grid x:Name="LayoutRoot" Background="Transparent">
<ListBox Name="TopSpotter_ListBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<!--<TextBlock Text="{Binding MemberId}"/>-->
<controls:TopSpotterItemControl DataContext="{Binding}"/>
<Grid Height="18"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Now this is good enough but what I want to do in my view is set data from my model like Booleans that determine whether or not I should show certain Grids etc. So if I try to set a dependency property explicitly in my control it fires and will run logic in the Getter/Setters for instance. HOWEVER if I try to set these custom objects from a binding source it won't actually set.
Here's what works:
<controls:TopSpotterItemControl ChampVisibility="True">
This way will trigger the ChampVisibility property and then in the code behind of the user control I can set visibilities.
Here's what fails but I want to work:
<controls:TopSpotterItemControl ChampVisibility="{Binding IsChamp">
In addition I can still set the DataContext to {Binding} and the result will be unchanged.
In this scenario IsChamp is part of my model that I would like to bind to this user control which I guess comes from the dataContext being set on the view from the viewModel. I'm not sure what I can do to get this so the bindings work etc. without having to set custom properties.
Finally, here's my user control:
public partial class TopSpotterItemControl : UserControl
{
public string MemberId
{
get
{
return this.MemberId_TextBlock.Text;
}
set
{
this.MemberId_TextBlock.Text = value;
}
}
public bool ChampVisibility {
set
{
if (value)
{
this.Champ_Grid.Visibility = System.Windows.Visibility.Visible;
}
}
}
public static readonly DependencyProperty MemberNameProperty =
DependencyProperty.Register("MemberId", typeof(string), typeof(TopSpotterItemControl), new PropertyMetadata(null));
public static readonly DependencyProperty ChampVisibilityProperty =
DependencyProperty.Register("ChampVisibility", typeof(bool), typeof(TopSpotterItemControl), new PropertyMetadata(null));
public TopSpotterItemControl()
{
InitializeComponent();
}
}
Bit long winded and I hope I made things on the issue clear. My one major hang up so far, and I'd like to abstract as much control as I can to the user control via dependency properties explicitly set in xaml, rather than setting up binding in its xaml that depend on the knowledge of a model. Thanks!
Your DependencyProperty is badly formed. (I also don't see Champ_Grid defined in your class or XAML, but I assume that is an ommission)
Setting ChampVisibility = true in code works because it is unrelated to the DependencyProperty.
You can tell easily because the default value for your DP is invalid. It will compile, but the instance constructor will through an exception if it is ever invoked.
new PropertyMetadata(null)
bool = null = exception
If you call GetValue(TopSpotterItemControl.ChampVisibilityProperty) from somewhere you can confirm all of the above.
You should make changes to instance fields in the property changed handler and declare the property like the following, it will work:
Note that the property has to change (not just be set) for the event to be raised.
public bool ChampVisibility
{
get { return (bool)GetValue(ChampVisibilityProperty); }
set { SetValue(ChampVisibilityProperty, value); }
}
public static readonly DependencyProperty ChampVisibilityProperty =
DependencyProperty.Register("ChampVisibility ", typeof(bool), typeof(TopSpotterItemControl), new PropertyMetadata(true, (s, e) =>
{
TopSpotterItemControl instance = s as TopSpotterItemControl;
instance.Champ_Grid.Visibility = instance.ChampVisibility ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
}));
Incidentally, your MemberId DependencyProperty is also completely wrong and cannot work.
Note:
The Binding on your TextBox works, because it is binding to the DataContext (your model), so it probably shows the right value.
The Dependency property in your UserControl will never be set though.
Use the propdp code-snippet in Visual Studio so you dont have to concern yourself with the complexities of Dependency Property declaration.
Also check this out for more info about Dependency Properties

I get Null Object in MVVM Model with silverlight two way binding

I'm new to silverlight and trying to save a form to the database via RIA Services using MVVM Pattern.
I get a textbox value in ViewModel when I bind a textbox to a string in twoway binding mode.
But When I bind a Object.Property to the textbox (Twoway binding) I get a null object in the ViewModel after I click on the save button.
Here is my code, please help me figure out where I am going wrong.
private tblSchool _school;
public tblSchool thisschool
{
get
{
return _school;
}
set
{
if (_school != value)
{
_school = value;
OnPropertyChanged("thisschool");
}
}
}
private void SaveSchool()
{
DomainServiceForDatabaseData service = new DomainServiceForDatabaseData();
service.tblSchools.Add(thisschool); //HERE I GET NULL VALUE
service.SubmitChanges();
}
Here is my XAML:
<Grid x:Name="LayoutRoot"
DataContext="{Binding Source={StaticResource SignUpViewModel}}">
<TextBox Height="23"
HorizontalAlignment="Right"
Margin="0,55,160,0"
Name="textBox1"
VerticalAlignment="Top"
Width="213"
Text="{Binding Path= thisschool.School_Name, Mode=TwoWay}" />
The backing field _school doesn't get initialized in your code sample.
Somewhere you will need to do _school = new tblSchool() or it will stay null forever.

How to bind local variable in WPF

I have silverlight usercontrol. This contains Service Entity object. see below
public partial class MainPage : UserControl
{
public ServiceRef.tPage CurrentPage { get; set; }
...
}
I need to bind CurrentPage.Title to TextBox
My xaml is here
<TextBox Text="{Binding Path=CurrentPage.Title, RelativeSource={RelativeSource self}}"></TextBox>
But it is not work.
How to do it?
In order for that to work, you'll have to implement INotifyPropertyChanged on your class and raise the PropertyChanged event for CurrentPage when it's set (this also means you won't be able to use auto properties; you'll have to use your own private instance backing variable and code the get { } and set { } yourself).
What's happening is the control is binding to the value before you've set CurrentPage. Because you aren't notifying anyone that the property has changed, it does not know to refresh the bound data. Implementing INotifyPropertyChanged will fix this.
Or you could just manually set the Text property yourself in the setter.
Change your markup to
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=CurrentPage.Title}" />
By assigning RelativeSource={RelativeSource self} your are telling the TextBlock to bind to itself and look for a property named CurrentPage on the TextBlock itself and not the parent Window.
set the UpdateSourceTrigger="PropertyChanged" in the XAML.

MVVM - ListBox SelectedItem Binding Property Going Null

So i have a listbox:
<ListBox x:Name="listbox" HorizontalAlignment="Left" Margin="8,8,0,8" Width="272" BorderBrush="{x:Null}" Background="{x:Null}" Foreground="{x:Null}" ItemsSource="{Binding MenuItems}" ItemTemplate="{DynamicResource MenuItemsTemplate}" SelectionChanged="ListBox_SelectionChanged" SelectedItem="{Binding SelectedItem}">
</ListBox>
and i have this included in my viewmodel:
public ObservableCollection<MenuItem> MenuItems
{
get
{
return menuitems;
}
set
{
menuitems = value;
NotifyPropertyChanged("MenuItems");
}
}
public MenuItem SelectedItem
{
get
{
return selecteditem;
}
set
{
selecteditem = value;
NotifyPropertyChanged("SelectedItem");
}
}
and also in my viewmodel:
public void UpdateStyle()
{
ActiveHighlight = SelectedItem.HighlightColor;
ActiveShadow = SelectedItem.ShadowColor;
}
So, the objective is to call UpdateStyle() whenever selectedchanged event is fired. So in the .CS file, i call UpdateStyle().
The problem is, whenever I get into the selectionchanged event method, my ViewModel.SelectedItem is always null.
I tried debugging this to see if the binding was working correctly, and it is. When I click on an item in the listbox, the SelectedItem Set is triggered, setting the value... but somewhere inbetween that and the selected changed (In the CS File) It gets reset to Null.
Can anyone help out?
Thanks
Edit:
I thought I might shed a little more light.
1. Click on an item in the list
2. SelectedItem.Set gets triggered, ViewModel.SeletedItem gets set correctly.
3. Enter the OnSelectionChanged Event in the .CS file.
4. Enter ViewModel.UpdateStyle()
5. SelectedItem Throws a Null Exception.
Wow, found a strange issue:
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource MainViewModelDataSource}}" d:DataContext="{d:DesignData /SampleData/MainViewModelSampleData.xaml}">
That code is generated by Expression Blend - and it was causing the issue. I erased all generated binding and just made a this.datacontext a new VM in the constructor of the XAML... now its working.
Thanks anyway, guys.
Look to see if your backing property (selecteditem) is getting set to NULL somewhere in your code.

Binding property to Silverlight dependency property independent of DataContext

I'm trying to make an Address control that has an IsReadOnly property, which will make every TextBox inside read only when set to true.
<my:AddressControl Grid.Column="1" Margin="5" IsReadOnly="True"/>
I've managed to do this just fine with a dependency property and it works.
Here's a simple class with the dependency property declared :
public partial class AddressControl : UserControl
{
public AddressControl()
{
InitializeComponent();
this.DataContext = this;
}
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register("IsReadOnly", typeof(bool),
typeof(AddressControl), null);
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
}
In the XAML for this codebehind file I have a Textbox for each address line:
<TextBox IsReadOnly="{Binding IsReadOnly}" Text="{Binding City, Mode=TwoWay}"/>
<TextBox IsReadOnly="{Binding IsReadOnly}" Text="{Binding State, Mode=TwoWay}"/>
<TextBox IsReadOnly="{Binding IsReadOnly}" Text="{Binding Zip, Mode=TwoWay}"/>
Like i said this works just fine.
The problem is that the Address control itself is bound to its parent object (I have several addresses I am binding).
<my:AddressControl DataContext="{Binding ShippingAddress, Mode=TwoWay}" IsReadOnly="True">
<my:AddressControl DataContext="{Binding BillingAddress, Mode=TwoWay}" IsReadOnly="True">
The problem is that as soon as I set DataContext to something other than 'this' then the binding for IsReadOnly breaks. Not surprising because its looking for IsReadOnly on the Address data entity and it doesn't exist or belong there.
I've tried just about every combination of binding attributes to get IsReadOnly to bind to the AddressControl obejct but can't get it working.
I've tried things like this, but I can't get IsReadOnly to bind independently to the AddressControl property instead of its DataContext.
<TextBox IsReadOnly="{Binding RelativeSource={RelativeSource Self}, Path=IsReadOnlyProperty}" Text="{Binding City, Mode=TwoWay}" />
I think I'm pretty close. What am I doing wrong?
With this answer (actually my own answer to a similar question) I have a good [better] solution.
I still have to iterate through the textboxes, but I don't have to set the actual value. I can create bindings in the codebehind - just not with XAML.
I think you're stuck, at least, if you want to do this just via binding. My guess is that you're going to have to resort to code-behind, presumably by iterating through your child textbox controls and setting their IsReadOnly propert as a side-effect of your Address control's IsReadOnly property.
Unlike some folks who think that any code sitting in a code-behind file is effectively an admission of failure, I don't get religious about it: if throwing some code into a code-behind is the easiest way to do something, that's where I put my code. On the contrary, if I have to spend half a day trying to figure out how to do something via binding that I could do in five minutes with a code-behind, that's failure, IMO.

Resources