Why can't I bind a string? - c#

Trying to wrap my old brain around WPF data binding.
Starting with the simplest scenario I could think of: An example online that worked, and I then simplified it.
I bound a simple string property to a TextBlock. Didn't work. When I then encapsulated that string inside a class of my own, it worked just fine!
Question: Why doesn't my string property work, but my class does?
<Window x:Class = "DataBindingOneWay.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Height = "350" Width = "600">
<Grid>
<StackPanel Orientation = "Vertical" HorizontalAlignment="Center" Margin="0,100,0,0">
<TextBlock Text="{Binding Name1}" />
</StackPanel>
</Grid>
</Window>
using System.Windows;
namespace DataBindingOneWay
{
public partial class MainWindow : Window
{
public class Employee
{
public string? Name1 { get; set; } = "Paul";
}
public string? Name1 { get; set; } = "Peter";
public MainWindow()
{
InitializeComponent();
DataContext = new Employee();
// DataContext = Name1;
}
}
}

Bindings operate on a data context that is set on elements deriving from FrameworkElement through the DataContext property. A data context is inherited in the tree of elements.
When data binding is declared on XAML elements, they resolve data binding by looking at their immediate DataContext property. The data context is typically the binding source object for the binding source value path evaluation. You can override this behavior in the binding and set a specific binding source object value. If the DataContext property for the object hosting the binding isn't set, the parent element's DataContext property is checked, and so on, up until the root of the XAML object tree. In short, the data context used to resolve binding is inherited from the parent unless explicitly set on the object.
If there is no data context set or you need to refer to other elements as bindings source, you need to parameterize a Binding with Source, ElementName or RelativeSource.
Bindings can be configured to resolve with a specific object, as opposed to using the data context for binding resolution.
Let use review how to bind a property defined in your MainWindow. There is no data context assigned initially. Therefore, all bindings to Name1 will fail. What can we do? Here are a few options (there are more).
Set the DataContext of MainWindow to this in code-behind.
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
This means all of the controls inherit the MainWindow as binding source. Consequently, we can bind the Name1 property like this:
<TextBlock Text="{Binding Name1}"/>
Here Name1 is the name (or property path) of the property to bind on the binding source. So if we simply assigned Name1 directly as DataContext of the window, then we would need to refer to the binding source itself, which is what {Binding} without a property path does.
public MainWindow()
{
InitializeComponent();
DataContext = Name1;
}
<TextBlock Text="{Binding}"/>
If you do not set a DataContext, you can still refer to elements using ElementName (requires an x:Name assigned to the target control) or RelativeSource which refers to an element in the element tree from the current element traversing parents until the root is reached.
<TextBlock Text="{Binding Name1, RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"/>
This example translates to: Search a binding source of type MainWindow up the element tree and if you find it, bind to its Name1 property. As you can see, this does not necessarily need a data context if the property is defined on the control itself like in your example. Nevertheless, generally you would use the DataContext property if nothing prevents it, since it is conveniently inherited.
I hope you saw that there is nothing really magical about it. Regarding the binding sytax (which can be confusing), there is a good documentation that should take away lots of your question marks:
Binding path syntax
Data binding overview (WPF .NET)
I got to think: WHAT field, or, rather, property in the String Class actually holds the 'value' of the string?
Bonus round: You do not need to worry about that at all. You bind to the string property and WPF knows how to display it, no need to use internal structures, but for educational purposes, the documentation states:
A string is a sequential collection of characters that's used to represent text. A String object is a sequential collection of System.Char objects that represent a string; a System.Char object corresponds to a UTF-16 code unit. The value of the String object is the content of the sequential collection of System.Char objects, and that value is immutable (that is, it is read-only).
The string type exposes this character array with its indexer property Chars.

Because there is no Name1 inside the object that you are binding to, when you bind to the string. That is, there is no Name1 inside the Name1 (what would be the result of Name1.Name1?). There is, however, a Name1 inside the Employee object (what would be the result of Employee.Name1?)

If you want to access Name1 property of MainWindow you should set DataContext to this (which is MainWindow instance) instead of Name1.
using System.Windows;
namespace DataBindingOneWay
{
public partial class MainWindow : Window
{
public class Employee
{
public string? Name1 { get; set; } = "Paul";
}
public string? Name1 { get; set; } = "Peter";
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}
}
or from the other side - when you want the Name1 property to be set as DataContext of MainWindow your binding should look like this:
<Window x:Class = "DataBindingOneWay.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Height = "350" Width = "600">
<Grid>
<StackPanel Orientation = "Vertical" HorizontalAlignment="Center" Margin="0,100,0,0">
<TextBlock Text="{Binding}" />
</StackPanel>
</Grid>
</Window>

Thanks to Jonathan's inspiring response, I got to think: WHAT field, or, rather, property in the String Class actually holds the 'value' of the string?
I played with everything, but nothing seemed to hold the actual string! (Weird).
That's where I got a crazy idea and tried simply
<TextBlock Text="{Binding}" />
And
DataContext = Name1;
And ... that worked!

Related

How properly use binding in wpf?

Let say I got app that is going to read data from database.
So in c# i got class like this:
public class Employee {
public string Name { get; set; }
public string Title { get; set; }
}
And my wpf window looks like:
<TextBlock Margin = "10" Width = "100" Text = "{Binding Name}" />
As I understand, to display in my window name of the employee I should use DataContext to bind object Employee with my wpf:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
DataContext = new Employee(...);
}
Ok, but what if i have another textbox to display object from another class?
public class Movie {
public string MovieTitle { get; set; }
}
<TextBlock Margin = "10" Width = "100" Text = "{Binding MovieTitle}" />
Where should I use DataContext to bind this all, that two textbox are display on my screen, and both display properties from another object?
It's not a must, but in WPF it is recommended to follow MVVM design patterns.
This means you need a View (as you created), a Model and a ViewModel.
The View should have a DataContext point to a ViewModel, and the binding in the View's XAML should be pointing to the ViewModel's properties.
So in your case, you can create a "main" ViewModel as your main DataContext object, and this ViewModel can have a string property called "EmployeeName" (or Employee ViewModel object with property "Name") and then the property can be assigned, or fetch the information directly from the Model.
Do not forget to fire a property change notification from the setter of any view model property, e.g. the PropertyChanged event of the INotifyPropertyChanged interface.
public string EmployeeName
{
get { return _employeeModel.Name; }
set
{
_employeeModel.Name = value;
PropertyChanged?.Invoke(
this, new PropertyChangedEventArgs(nameof(EmployeeName)));
}
}
If you're following MVVM properly:
Your ViewModel must not know the View, it can only know Models or other ViewModels.
Your Model must not know the View or the ViewModel, it can only know other Models.
As others were trying to point out, add another thing to the main class. Or, as Yair mentioned to create a view model. Try to think of it this way.
public class MainWindowViewModel
{
public MainWindowViewModel()
{
OneEmployee = new Employee();
OneMovie = new Movie();
}
public Employee OneEmployee {get; set;}
public Movie OneMovie {get; set;}
// any other things you want to expose, button relay commands labels, etc...
public string SomeOtherThing {get; set;}
}
Now, in your MainWindow (or whatever other secondary window you develop), in its constructor, just set
DataContext = new MainWindowViewModel();
Now, back to your XAML Your xaml's data context is to the overall view model that has BOTH objects, a label, and whatever else you want. When binding and its all in the same level in the xaml, you can do binding to OneEmployee.Name, or OneMovie.Title, or whatever other parts going on.
However, let say you are sectioning off the display and have one area designated for the employee information and another based on a movie. You can set a data context to that sub-component to the object in question, so the inner controls are now defaulted to that. Removes the need of "object.property" notation within. Ex:
<UserControl DataContext="{Binding OneEmployee}">
<Grid>
<define your grid rows/columns for example>
<Label Content="Name" Grid.Row="0" Grid.Column="0" />
<TextBox Width="100" Grid.Row="0" Grid.Column="1"
Text="{Binding Name}" />
</Grid>
</UserControl>
Notice above the entire "UserControl" has its default data context to just the OneEmployee object. So everything within can refer to properties exposed directly on that object. In this example, the entire context of the user control is to show information about the one employee and not the movie. Same can be done for a single movie.
I actually like doing it this way and create individual user controls with inner grid type content to span its own rows/columns. Then, when I put them into a main view area, I dont have to worry about messing with other nested controls, grids. The single user-control is all self-contained with all its alignments, borders, etc. If I need to adjust employee info layout, I just change that one class, not the outer view that the employee is displayed within.

Why databinding doesn't work on UserControl? [duplicate]

This question already has answers here:
Issue with DependencyProperty binding
(3 answers)
XAML binding not working on dependency property?
(1 answer)
Closed 3 years ago.
I'm trying to make a simple user control in WPF/C#. Everything seems to work except for databinding to property in datacontext.
I tried making extremely simplified example to see better what I'm doing wrong. I'm quite new to WPF in general, so I think I'm doing Dependency Properties wrong somehow. Might be in the binding itself, but that works normally for other elements, like TextBox.
This seemed to be similiar problem, but answer didn't seem to work in my case: Why DataBinding is not propagating to UserControl
MainWindow.xaml (root tag omitted)
<StackPanel>
<local:UserControl1 TextToDisplay="{Binding BoundableText}" />
<TextBlock Text="{Binding BoundableText}" />
</StackPanel>
UserControl1.xaml (root tag omitted)
<TextBlock Text="{Binding TextToDisplay}" />
MainWindow.xaml.cs:
using System.Windows;
using System.Windows.Controls;
namespace UserControlTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
BoundableText = "This text is bound";
}
public string BoundableText { get; set; }
}
public partial class UserControl1 : UserControl
{
public static readonly DependencyProperty TextToDisplayProperty =
DependencyProperty.Register(nameof(TextToDisplay), typeof(string), typeof(UserControl1), new PropertyMetadata("Default text"));
public string TextToDisplay
{
get => (string)GetValue(TextToDisplayProperty);
set => SetValue(TextToDisplayProperty, value);
}
public UserControl1()
{
InitializeComponent();
DataContext = this;
}
}
}
The 2 elements should be also identical in content, displaying text which is set in code-behind ("This text is bound"). TextBox works as it should, but UserControl1 has just the default text. What makes this case different from the first? Can I get it to work the same?
Note: I also tried to bind to other element's property, that works nicely. Also binding from code-behind works. However, this should be possible from xaml itself. In actual use case the control will be in a DataTemplate.
Don't set the DataContext of the UserControl to itself in the constructor:
DataContext = this;
Then it won't inherit the DataContext from the parent window.
To bind to the TextToDisplay dependency property in the UserControl, you could use a RelativeSource:
<TextBlock Text="{Binding TextToDisplay, RelativeSource={RelativeSource AncestorType=UserControl}}" />

WPF ComboBox SelectedValue binding with null value shows up blank

I have a problem while trying to bind 2 or more Comboboxes SelectedValue to a property, that is null.
Only 1 of the comboboxes bound to this property will show the real value.
Below is my Xaml where i use DataTemplate to select a Combobox for presentation of the viewModel.
Xaml:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:PropertyValueViewModel}">
<ComboBox SelectedValue="{Binding Value}" ItemsSource="{Binding SelectableValues}" DisplayMemberPath="Description" SelectedValuePath="Value"/>
</DataTemplate>
</Window.Resources>
<StackPanel>
<Label Content="These uses template:"></Label>
<ContentPresenter Content="{Binding ValueSelector}"></ContentPresenter>
<ContentPresenter Content="{Binding ValueSelector}"></ContentPresenter>
<ContentPresenter Content="{Binding ValueSelector}"></ContentPresenter>
</StackPanel>
And the code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ValueSelector = new PropertyValueViewModel()
{
SelectableValues = new List<SelectableValue>()
{
new SelectableValue("NULL", null),
new SelectableValue("1", 1)
},
Value = null
};
DataContext = this;
}
public static readonly DependencyProperty ValueSelectorProperty = DependencyProperty.Register(
"ValueSelector", typeof(PropertyValueViewModel), typeof(MainWindow), new PropertyMetadata(default(PropertyValueViewModel)));
public PropertyValueViewModel ValueSelector
{
get { return (PropertyValueViewModel)GetValue(ValueSelectorProperty); }
set { SetValue(ValueSelectorProperty, value); }
}
}
/// <summary>
/// My viewModel
/// </summary>
public class PropertyValueViewModel
{
public object Value { get; set; }
public object SelectableValues { get; set; }
}
/// <summary>
/// The items in the combobox
/// </summary>
public class SelectableValue
{
public SelectableValue(string header, object value)
{
Value = value;
Description = header;
}
public object Value { get; set; }
public string Description { get; set; }
}
Now i am wondering why only 1 of them can show the NULL value at startup?
I can change the value in any of them, and they will all sync with the value in the property - if i select 1 and then back to NULL, they will all show NULL.
It seems like its only the initial value is not shown correctly.
If i avoid using DataTemplate the binding works too.
Does anyone know why the DAtaTemplate behaves this way?
Interesting problem.
Fundamentally, this appears to be caused by your choice to use null as one of the selectable values. null, of course, has special meaning, for C#, .NET, and WPF. The problem also involves the order in which the initialization of the ComboBox element is done. The SelectedValuePath property is initialized after the SelectedValue property.
This means that as your program is starting up and the ComboBox elements are created, when null is assigned to the SelectedValue property through its binding, the ComboBox does not yet have enough information to handle that value as a legitimate item selection. Instead, it interprets it as no selection at all.
Why does the last ComboBox still get initialized the way you want? I'm not really sureā€¦I didn't investigate very far regarding that. I could speculate, but the odds of my guessing correctly seem low so I won't bother. Since it's the anomaly and not necessarily in keeping with expected behavior (based on above, even if the behavior is the desired behavior) I'll chalk it up to one of WPF's many "quirks". :)
I found several work-arounds for the issue:
Don't use null as a selectable value. If every selectable value is non-null, then the non-null value used to initialize each element's SelectedValue property is retained and when the SelectedValuePath is initialized, the current selection for the ComboBox is set correctly.
Don't use SelectedValuePath. Instead, just bind to SelectedItem and initialize the Value property with the desired SelectableValue class instance (e.g. the first one in the list).
In the ComboBox's Loaded event, refresh the target of the binding.
The first two are significant departures from your current design. Personally, if at all possible I would go with one or the other. It seems to me that there's a clear danger in using null as a selectable value in a ComboBox, and this may not be the only oddity you run into. In the long run, maintenance of this part of the code may cost a lot more if you continue to use null.
That said, the third option does work, and if you're lucky, the only real hazard in using null is on initialization. My proposed work-around for that option would look something like this:
XAML:
<DataTemplate DataType="{x:Type local:PropertyValueViewModel}">
<ComboBox SelectedValue="{Binding Value}"
ItemsSource="{Binding SelectableValues}"
DisplayMemberPath="Description"
SelectedValuePath="Value"
Loaded="comboBox_Loaded"/>
</DataTemplate>
C#:
private void comboBox_Loaded(object sender, RoutedEventArgs e)
{
ComboBox comboBox = (ComboBox)e.OriginalSource;
BindingOperations.GetBindingExpression(comboBox, ComboBox.SelectedValueProperty)
.UpdateTarget();
}
This forces WPF to update the target (i.e. the SelectedValue property of the control). Since at this point, the SelectedValuePath has been set, assigning null to the property this time correctly updates the selected item for the ComboBox.
By the way, I would strongly recommend that you disambiguate the names of the Value properties in your models. Having two different Value properties used for bindings in a single XAML element is very confusing. I would use, for example, SelectedValue and ItemValue, for the PropertyValueViewModel class and the SelectableValue class, respectively.

Unable to properly data bind in WPF C#

I'm a newbie to WPF and data binding and after hours of binging and searching Stackoverflow I have not been able to find a comprehensive solution. I am trying to display text on a TextBlock control using data binding on my KinectWindow.xaml:
<TextBlock x:Name="InitText"
TextWrapping="Wrap"
Text="{Binding Source=ScanInitTextA,
Path=ScanInitTextA,
UpdateSourceTrigger=PropertyChanged}"
The complimentary KinectWindow.xaml.cs class has the following property:
string ScanInitText = "Preparing for Initial Scan.";
string ScanInitTextA
{ get { return (ScanInitText) ; }
set { ScanInitTextA = value; }
}
I've made numerous attempts, either by binding the property directly from the class or from the xaml. I usually get this error when trying to do anything:
System.Windows.Data Error: 40 : BindingExpression path error: 'ScanInitTextA' property not found on 'object' ''String' (HashCode=1828304777)'.
BindingExpression:Path=ScanInitTextA;
DataItem='String' (HashCode=1828304777);
target element is 'TextBlock' (Name='InitText');
target property is 'Text' (type 'String')
From what I understand, ScanInitTextA cannot be found in the object String?
Finally, I know that when I try a similar approach from a different class (that isn't KinectWindow.xaml.cs, by referencing the class in the xaml and changing the binding source to the name of that class), the data binding does work, but for other reasons I'd prefer to do it through this class.
Thanks in advance. :)
Try this:
<TextBlock x:Name="InitText"
TextWrapping="Wrap"
Text="{Binding Path=ScanInitTextA}"
Error message says that you trying to find property ScanInitTextA on the string object itself. I think the Source for current TextBlock was assigned before (maybe as DataContext).
Have you tried
<TextBlock x:Name="InitText"
TextWrapping="Wrap"
Text="{Binding Path=ScanInitTextA,
UpdateSourceTrigger=PropertyChanged}"
If you have set the DataContext of you view to self then giving Source is wrong. Just update your binding as:
<TextBlock x:Name="InitText"
TextWrapping="Wrap"
Text="{Binding Path=ScanInitTextA,
UpdateSourceTrigger=PropertyChanged}"/>
Update
What is needed is a way to bind to the property of the main window. Here is a way to do that binding
<Window x:Name="KinectWindow"
Title="My Kinect Show"
...>
<TextBlock Text="{Binding ScanInitTextA, ElementName=KinectWindow}" />
Note that you will still need to make ScanInitTextA do a property changed notification if you expect its value will be changed by something and that change needs to be displayed automatically. See #1 and #2 below.
Original Advice to Adhere to MVVM type system and put the VM on the Data Context of the Window
First off whatever class is holding ScanInitTextA needs to implement INotifyPropertyChanged and make ScanInitTextA public.
Secondly a better binding methodology is done by setting the page's data context to the class which has the INotifyPropertyChanged. That is done because it centralizes all of your data to be shown in one location and that a page's data context is inherited by all the controls, so at that point each of the page's controls simply bind to the property name. This is basic MVVM where the VM (view model) has the INotifyPropertyChanged.
Example
We want to show Members, a list of strings, on our page in a list box. Ultimately our binding will be just {Binding Members}.
View Model
public class MainVM : INotifyPropertyChanged
{
private List<string> _Members;
public List<string> Members
{
get { return _Members; }
set { _Members = value; OnPropertyChanged(); }
}
public MainVM()
{
// Simulate Asychronous access, such as to a db.
Task.Run(() =>
{
Members = new List<string>() {"Alpha", "Beta", "Gamma", "Omega"};
MemberCount = Members.Count;
});
}
/// <summary>Event raised when a property changes.</summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>Raises the PropertyChanged event.</summary>
/// <param name="propertyName">The name of the property that has changed.</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Page Codebehind
public partial class MainWindow : Window
{
public MainVM ViewModel { get; set; }
public MainWindow()
{
InitializeComponent();
// Set the windows data context so all controls can have it.
DataContext = ViewModel = new MainVM();
}
}
Page Xaml with binding
<ListBox Name="lbData"
ItemsSource="{Binding Members}"
SelectionMode="Multiple"
Margin="10" />
This example is taken from my blog article:
Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding.

Loading XAML to C# for Data Binding

Ok, we are trying out XAML for our GUI now (and learning as we go)...I have been able to do the data binding without a problem in XAML and C# independent of one another, but now comes the time I need to pass values back and forth and I'm a bit lost. When I compile and try to navigate to the page, it is throwing a XamlParseException: Specified class name doesn't match actual root instance type. Remove Class directive or provide an instance via XamlObjectWriterSettings.RootObjectInstance. Line 5 position 2.
Any help or a gentle shove in the right direction is greatly appreciated :)
Here's where I am:
namespace TheAirline.GraphicsModel.PageModel.PageFinancesModel
{
/// <summary>
/// Interaction logic for PageFinances.xaml
/// </summary>
public partial class PageFinances : Page
{
private Airline Airline;
public PageFinances(Airline airline)
{
InitializeComponent();
this.Language = XmlLanguage.GetLanguage(new CultureInfo(AppSettings.GetInstance().getLanguage().CultureInfo, true).IetfLanguageTag);
this.Airline = airline;
Page page = null;
//loading the XAML
using (FileStream fs = new FileStream("TheAirline\\GraphicsModel\\PageModel \\PageFinancesModel\\PageFinances.xaml", FileMode.Open, FileAccess.Read))
{
page = (Page)XamlReader.Load(fs);
}
//finding XAML element and trying to set the value to a variable
string airlineCash = GameObject.GetInstance().HumanAirline.Money.ToString();
TextBox cashValue = (TextBox)page.FindName("cashValue");
cashValue.DataContext = airlineCash;
}
}
}
And the first few lines of the XAML:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:AirlineModel="clr-namespace:TheAirline.Model.AirlineModel"
mc:Ignorable="d"
x:Class="TheAirline.GraphicsModel.PageModel.PageFinancesModel.PageFinances"
xmlns:c="clr-namespace:TheAirline.GraphicsModel.Converters"
...>
</Page>
Bindings in XAML are resolved against the object that is assigned to the DataContext property of any given XAML element. The value of that property (as well as many other properties) Is Inherited in any given Visual Tree from parent elements to child elements.
for instance, given this class:
public namespace MyNamespace
{
public class ViewModel
{
public string Name {get;set;}
public bool IsActive {get;set;}
}
}
and this XAML:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace"
FontSize="20">
<Window.DataContext>
<local:ViewModel>
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Path=Name}"/>
<CheckBox IsChecked="{Binding Path=IsActive}"/>
<StackPanel>
</Window>
All four objects defined in XAML, the Window, the StackPanel, the TextBox, and the CheckBox, will have a FontSize of 20, and the instance of the ViewModel class assigned to their DataContext property. Therefore all bindings (Except bindings with a specified ElementName, RelativeSource, or Source) will be resolved against that instance.
It would be exactly the same if the property was assigned in code instead of in XAML:
public MyWindow() //Window Constructor
{
InitializeComponent();
this.DataContext = new ViewModel(); //Note that keyword "this" is redundant, I just explicity put it there for clarity.
}
Because of this, there is no need to set the DataContext property to each element explicitly, as the framework is already taking care of that.
Also, notice that in XAML, most built-in Markup Extensions have a default constructor convention that allows you to abbreviate their usage. In the case of the Binding Markup Extension, the default constructor has the Path property, therefore this:
<TextBox Text="{Binding Path=Name}"/>
is exactly the same as this:
<TextBox Text="{Binding Name}"/>
Now, for property changes in the underlying DataContext to be automatically passed from the binding source (ViewModel) to the binding target (XAML-defined objects), the source object must implement the System.ComponentModel.INotifyPropertyChanged interface and raise the PropertyChanged event every time a property changes.
Therefore, in order to support Two-Way Binding, the example class should look like this:
public namespace MyNamespace
{
public class ViewModel: INotifyPropertyChanged
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
NotifyPropertyChanged("Name");
}
}
private bool _isActive;
public bool IsActive
{
get
{
return _isActive;
}
set
{
_isActive = value;
NotifyPropertyChanged("IsActive");
}
}
}
public void NotifyPropertyChanged (string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
}
}
Notice that the ViewModel class has no dependency or direct reference to any of the XAML-defined objects, but still it contains the Values of the properties that will appear in the UI. This allows for a complete decoupling between UI and application logic/data known as the MVVM Pattern. I strongly suggest you research on that topic if you expect to be successful in programming in C# + XAML, because it is a radical mindshift when compared to other, traditional UI paradigms.
For example, something like this is not recommended in XAML-based applications:
if (myWindow.CheckBox1.IsChecked)
//Do Something
because that would mean that you're coupling the application logic and making it dependant on the state of UI elements, which is precisely what you need to avoid.
Notice that all the links and all the concepts referenced in this answer pertain to WPF, but are also applicable to Silverlight and WinRT. Since you did not specify which of the three XAML-based frameworks you're using, I posted the WPF ones, which is what I'm most familiar with.

Categories