I want to create a UserControl, that essentially is a Label with a TextBox. Now I want to be able to Bind TextBox.Text to different values.
For this I created a DependencyProperty in my UserControl and am now trying to bind something to that newly created DependencyProperty, but the Text seems not to get updated.
My UserControl1.xaml looks like this:
<UserControl x:Class="WpfApplication1.UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="48" d:DesignWidth="200">
<Grid>
<WrapPanel Height="48" HorizontalAlignment="Left" Name="wrapPanel1" VerticalAlignment="Top" Width="200">
<Label Content="Label" Height="48" Name="label1" Width="100" />
<TextBox Height="48" Name="textBox1" Width="100" />
</WrapPanel>
</Grid>
And my UserControl1.xaml.cs looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
private string value;
public string Value
{
get { return value; }
set
{
this.value = value;
textBox1.Text = value;
Trace.TraceInformation("value set in UserControl1");
}
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(string), typeof(UserControl1));
public UserControl1()
{
InitializeComponent();
}
}
}
I am using the UserControl like this:
<my:UserControl1 x:Name="userControl11" Value="{Binding Path=Name}" />
with DataContext set to an object that has a Name property and implements INotifyPropertyChanged for this property.
You put connection between TextBox's Text and UserControl's Value in wrong place. The CLR property is used for convenience but it is not used by Bind Engine. You need bind TextBox's Text to Usercontrol's Value explicitly on XAML or code behind, such as (assuming you give your user control a name called root):
<TextBox x:Name="textBox1" Text="{Binding Path=Value, ElementName=root}"/>
You cannot add additional logic or code to the get or set accessor for a property that wraps a dependency property. It will not be executed.
The reason for this, is because the WPF designer will actually generate code to use the DependencyProperty directly. The get/set property is there just for convenience if you use it in the code. Because you want the DependencyProperty and the property's get/set to do the same thing, you should only call GetValue and SetValue in the get/set accessors while passing in the related dependency property.
See these tutorials:
Dependency Properties
Dependency Properties Overview
Take a look at this implementation. It uses a very simple MVVM design to obtain databinding.
Basically this is what it's doing:
You have your UserControl (the View) that sets it's DataContext to a corresponding ViewModel.
The TextBox on the View is then bound to a public property in that ViewModel
By implementing INotifyPropertyChanged, you are enabling your ViewModel to effectively update the UI anytime it changes the value of the Text property.
This can repeated for any number of bindings and applied to many different types such as Lists, ObservableCollections, integers.
View
<UserControl x:Class="WpfApplication1.UserControl1"
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"
mc:Ignorable="d" d:DesignHeight="48" d:DesignWidth="200">
<Grid>
<WrapPanel Height="48" HorizontalAlignment="Left" Name="wrapPanel1" VerticalAlignment="Top" Width="200">
<Label Content="Label" Height="48" Name="label1" Width="100" />
<TextBox Height="48" Name="textBox1" Width="100" Text={Binding Text} />
</WrapPanel>
</Grid>
View Code-Behind
namespace WpfApplication1
{
using System.Windows;
using System.Windows.Controls;
public partial class UserControl1: UserControl
{
public UserControl1()
{
DataContext = new UserControl1ViewModel();
InitializeComponent();
}
}
}
ViewModel
namespace WpfApplication1
{
using System.Collections.ObjectModel;
using System.Windows.Controls;
class UserControl1ViewModel : INotifyPropertyChanged
{
// Ultimately, this field (text) would be moved to a model along with
// any other data fields for this view but for the sake of space,
// I've put it in the ViewModel.
private string text = "";
public string Text
{
get { return text; }
set
{
text = value;
RaisePropertyChanged("Text");
}
}
public MainWindowViewModel()
{
Text = "Hello!";
}
// This is the implementation of INotifyPropertyChanged that is used
// to inform the UI of changes.
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Good luck!
Related
I am writing a User Control named "GridAndChart" that can be filled with values at Design-Time just like this:
<local:GridAndChart HorizontalAlignment="Left"
VerticalAlignment="Top" Width="660"
Height="342"
Margin="28,29,0,0"
NameX="Auslastung in %"
NameY="Wirkungsgrad in %"
MinValueX="0"
MaxValueX="100"
MinValueY="0"
MaxValueY="100"
TitleOfChart="Kennlinie Wirkungsgrad"
Xvals='12,323,43,55,65,7'
Yvals='60,99,99,99,99,99'
/>
Most of the Properties you can see there (Like TitleOfChart, Xvals,...) I defined in the Code-Behind-File of my User-Control as Dependency-Properties.
My Problem is that only those Dependency-Properties are displayed correctly in my Test-Window, that are bound in the UserControl-XAML and therefore invoked by the initializeComponent(), like for example TitleOfChart. By displayed correctly I mean: Display of the Design-time-value from the XAML where I include my UserControl. The other dependency properties don't display correctly because they show only their default value.
From my example you will see that the Evaluation of my dummy-calculations will happen with the default values of the Dependency Properties. Not, after that they got their "Design-Time-Values", read out from the Main.xaml.
Thankyou for your help!
EDIT: Reproducible Code (4 Files)
File 1 and 2: The Window that uses the Control and it's Code-Behind
MainWindow.xaml
<Window x:Class="MinimalReproducibleExample.MainWindow"
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:local="clr-namespace:MinimalReproducibleExample"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:SimpleUserControl Working="I defined this Text at Design time" NotWorking="1,2,3,4"/>
</Grid>
</Window>
MainWindow.xaml.cs (I left it empty)
using ...
namespace MinimalReproducibleExample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
File 3 and 4: The User-Control and it's Code-Behind
SimpleUserControl.xaml
<UserControl x:Class="MinimalReproducibleExample.SimpleUserControl"
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:MinimalReproducibleExample"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Name="TextBox1XAML" />
<TextBox Grid.Row="1" Name="TextBox2XAML" />
</Grid>
</UserControl>
SimpleUserControl.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MinimalReproducibleExample
{
public partial class SimpleUserControl : UserControl
{
public SimpleUserControl()
{
InitializeComponent();
string notWorking = NotWorking;//just to show that there happens some calculation with the values
int a = Convert.ToInt32(notWorking.ElementAt(0)); //before they are displayed
int b = Convert.ToInt32(notWorking.ElementAt(1));
int c = a + b;
TextBox2XAML.Text = c.ToString();
}
public string Working
{
get { return GetValue(WorkingProperty).ToString(); }
set { SetValue(WorkingProperty, value); }
}
public static readonly DependencyProperty WorkingProperty = DependencyProperty.Register(nameof(Working), typeof(string), typeof(SimpleUserControl), new PropertyMetadata("The default is working.", (s, e) => (s as SimpleUserControl).TextBox1XAML.Text = (string)e.NewValue));
public string NotWorking
{
get { return GetValue(NotWorkingProperty).ToString(); }
set { SetValue(NotWorkingProperty, value); }
}
public static readonly DependencyProperty NotWorkingProperty = DependencyProperty.Register(nameof(NotWorking), typeof(string), typeof(SimpleUserControl), new PropertyMetadata("The default is also working.", (s, e) => (s as SimpleUserControl).NotWorking = (string)e.NewValue));
}
}
In your MCVE if you put the code to the Loaded event handler of your usercontrol, then all will work as expected. See example:
Usercontrol:
public partial class SimpleUserControl : UserControl
{
public string SimpleTxtProp { get; set; } = "AAA";
public SimpleUserControl()
{
//Constructor being called from InitializeComponent() of parent element. All properties are initialized with values from code behind,
//after object creation is finished, it's property will be initialized with values set in parent element for this control.
InitializeComponent();//Content of control being initialized: constructor -> InitializeComponent()
var isAAA = SimpleTxtProp == "AAA";//true
Loaded += (o, e) =>
{
var isBBB = SimpleTxtProp == "BBB"; //true
};
}
}
MainWindow:
<local:SimpleUserControl SimpleTxtProp="BBB"/>
It doesn't matter whether you consider dependency or simple property.
InitializeComponent() of MainWindow does
trigger the instantiation of SimpleUserControl, hence constructor
with default values/values from code behind being called,
then the properties of the created object being set.
So once an istance of "SimpleUserControl" is loaded, it has the values, which was set in XAML of MainWindow.
This question already has answers here:
WPF Binding Image Source
(2 answers)
Closed 5 years ago.
I have been working on a small sample Wpf Mvvm project for experimenting with INotifyPropertyChanged interface. The project actually works correctly, but the problem that I am having is that the project only works correctly if I set the DataContext in the code behind of MainWindow.xaml. If I try to set the DataContext in the xaml markup then some of the features of the project don't work. The UI contains a textblock, textbox (for entering text to display in the textblock OnPropertyChanged) and submit button (which really does nothing except provide a place to lose focus from textbox) and 3 other buttons (color buttons) for changing the background color of the UI. The default color of the UI is orange -- until the color is changed by clicking any of the color buttons
There are 3 viewModels, PersonViewModel (which the textbox binds to), BackgroundViewModel (for the color buttons) and a MainViewModel which combines the two other viewModels. The viewModels reside in the viewModels folder of the project. There is also an ObservableObject class (ViewModelBase class basically) which implement INotifyPropertyChanged interface and gets inherited by PersonViewModel and BackgroundViewModel. ObservableObject.cs resides in the root folder of the project.
The Project isn't pure Mvvm. The color buttons use a click event in the code behind of MainWindow.xaml. If I set the DataContext in the Code behind of MainWindow.xaml everything works correctly. If I set the DataContext in the xaml markup -- the textbox/textblock features works but the color buttons won't change the background color of the UI. When I step through the code it runs through all the code correctly but the UI background colors don't change. I am guessing it is a binding thing.
The sample project can be downloaded here
The code is below. How can I make this project function correctly if I set the DataContext in the xaml markup? I tried the following binding on the Grid which WILL set the default orange color for the UI, but the color buttons don't work:
<Grid Background="{Binding Background.Color}" DataContext="{StaticResource bc}">
--MainWindow.xaml
<Window x:Class="NotifyChangeExample.MainWindow"
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:local="clr-namespace:NotifyChangeExample"
xmlns:VM="clr-namespace:NotifyChangeExample.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="525">
<!--<Window.DataContext>
<VM:MainViewModel />
</Window.DataContext>-->
<Window.Resources>
<VM:MainViewModel x:Key="bc" />
</Window.Resources>
<Grid Background="{Binding Background.Color}" DataContext="{StaticResource bc}">
<!--<Grid Background="{Binding Background.Color}">-->
<DockPanel LastChildFill="False" Margin="0,82,0,0">
<StackPanel Width="150" DockPanel.Dock="Top">
<TextBlock Text="{Binding Person.Name, StringFormat=Welcome (0)}" />
<TextBox Text="{Binding Person.Name, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />
<Button>Submit</Button>
</StackPanel>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" DockPanel.Dock="Bottom" >
<Button Click="Red_Clicked">Red Background</Button>
<Button Click="Blue_Clicked">Blue Background</Button>
<Button Click="Yellow_Clicked">Yellow Background</Button>
</StackPanel>
</DockPanel>
</Grid>
</Window>
--MainWindow.xaml.cs
using NotifyChangeExample.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace NotifyChangeExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
MainViewModel _main = new MainViewModel();
public MainWindow()
{
InitializeComponent();
//DataContext = _main;
}
private void Red_Clicked(object sender, RoutedEventArgs e)
{
_main.SetBackground(Brushes.Red);
}
private void Blue_Clicked(object sender, RoutedEventArgs e)
{
_main.SetBackground(Brushes.Blue);
}
private void Yellow_Clicked(object sender, RoutedEventArgs e)
{
_main.SetBackground(Brushes.Yellow);
}
}
}
--ObservableObject.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NotifyChangeExample
{
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
}
--PersonViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NotifyChangeExample.ViewModels
{
public class PersonViewModel : ObservableObject
{
private string _name;
public string Name
{
get
{
if (string.IsNullOrEmpty(_name))
return "Unknown";
return _name;
}
set
{
_name = value;
OnPropertyChanged("Name");
}
}
}
}
--BackgroundViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace NotifyChangeExample.ViewModels
{
public class BackgroundViewModel : ObservableObject
{
private Brush _color;
public Brush Color
{
get
{
if (_color == null)
return Brushes.Orange;
return _color;
}
set
{
_color = value;
OnPropertyChanged("Color");
}
}
}
}
--MainViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace NotifyChangeExample.ViewModels
{
public class MainViewModel
{
public PersonViewModel Person { get; private set; }
public BackgroundViewModel Background { get; private set; }
public MainViewModel()
{
Person = new PersonViewModel();
Background = new BackgroundViewModel();
}
public void SetBackground(Brush brushColor)
{
Background.Color = brushColor;
}
}
}
Your code behind is using the _main object so if you want to set the DataContext in the XAML, you just need to set _main using the DataContext.
So in the XAML you would have
<Window.DataContext>
<VM:MainViewModel />
</Window.DataContext>
and in your code behind you would set _main by casting the DataContext to a MainViewModel
MainViewModel _main;
public MainWindow()
{
InitializeComponent();
_main = (MainViewModel) DataContext;
}
Alternatively, remove the DataContext from XAML, and use this MainWindow constructor:
private readonly MainViewModel _main = new MainViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _main;
}
When you are binding your ViewModel from XAML it can't work, because in your code-behind you are setting the colors to your local ViewModel "_main". But _main is not bound to the View, bc is.
In my XAML I am doing the following
<Label Content="{Binding ElementName=Root, Path=UserData.Email, Mode=OneWay}" />
the Root element is my Window itself and the UserData Is a get; private set; auto property in my codebehind file, the Email property is get-only and is of type string.
the UserData object gets set after the user has logged in. But the binding is not taking the value from the object. I have verified that the object does indeed contain the correct data and isn't null. What am I missing here?
I went ahead and created a hello world version for this. Here is the xml. This should simply change the banner when the button is clicked to the text in the text box. I couldn't find a super simple example so I just made one. Obviously there are way more advanced ways to do this but it should make for a simple version to build from.
<Window x:Class="Hello_World.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Label Name="MyLabel" Content="{Binding MyLabel}" HorizontalAlignment="Left" Margin="58,37,0,0" VerticalAlignment="Top" Height="65" Width="423" FontSize="44"/>
<TextBox Name="MyTextBox" HorizontalAlignment="Left" Height="28" Margin="163,162,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="163"/>
<Button Content="Change Banner" HorizontalAlignment="Left" Margin="251,209,0,0" VerticalAlignment="Top" Width="109" Click="Button_Click"/>
</Grid>
</Window>
Next is the ModelView that implements the INotifyPropertyChanged interface. Note that your properties must be public properties with a getter, setter and backing field. This allows you to call the OnPropetyChanged() method whenever the property is set.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hello_World
{
public class MainViewModel: INotifyPropertyChanged
{
private string _myLabel;
public string MyLabel
{
get { return _myLabel; }
set
{
_myLabel = value;
OnPropertyChanged(nameof(MyLabel));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propetyName)
{
if(PropertyChanged != null)
PropertyChanged(this,new PropertyChangedEventArgs(propetyName));
}
}
}
Lastly the MainWindow. Set the DataContext in the main constructor. Note I could have set the DataContext of the main grid and all of its children would inherit the same DataContext. This would keep you from having to set all of the components' individually.
namespace Hello_World
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private MainViewModel MyViewModel;
public MainWindow()
{
InitializeComponent();
MyViewModel = new MainViewModel();
// Here's where I'm setting the object to look at.
DataContext = MyViewModel;
// Now I don't need to access the textbox directly.
MyViewModel.MyLabel = "Hello World";
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Note: ICommand is a more advanced topic.
MyViewModel.MyLabel = MyTextBox.Text;
}
}
}
I am trying to implement an intermediary class ViewModelSelector that sets up and selects the current View/ViewModel to be shown as part of the main view main window MainView.xaml. I am trying to do this by defining a DataTemplate for ViewModel1 (see below) inside MainView.xaml and then using a ContentControl which I bind to the property CurrentViewModel of ViewModelSelector. The ViewModelSelector assigns ViewModel1 to its property CurrentViewModel. The idea is then to extend this with more DataTemplates and ViewModels and using UserControls to have the ViewModelSelector setup and decide which ViewModel to show (ViewModel1, ViewModel2, etc.). However for some reason this is not working:
When binding the ContentControl to ViewModelSelector.CurrentViewModel using <ContentControl Content="{Binding ViewModelSelector.CurrentViewModel}"/> the datatemplate is not shown (see MainView.xaml below). But no other error is thrown (that I can tell).
For debugging purposes I also created a CurrentViewModelInMainViewModel property in MainViewModel.cs which I set to ViewModelSelector.CurrentViewModel (CurrentViewModelInMainViewModel = ViewModelSelector.CurrentViewModel;). Binding directly to it (<ContentControl Content="{Binding CurrentViewModelInMainViewModel}"/>) works and the DataTemplate is shown.
So what am I doing wrong?
Here is the elided code. I hope I did not put any error in it, as I am not at work right now and can't test ...
My MainViewModel.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProgramEditor.ViewModel
{
using GalaSoft.MvvmLight;
using ProgramEditor.View;
class MainWindowViewModel : ViewModelBase
{
private ViewModelSelector ViewModelSelector;
public ViewModelSelector ViewModelSelector
{
get { return ViewModelSelector; }
set {
ViewModelSelector = value;
RaisePropertyChanged("ViewModelSelector");
}
}
private ViewModelBase currentViewModelInMainViewModel;
public ViewModelBase CurrentViewModelInMainViewModel
{
get
{
return currentViewModelInMainViewModel;
}
set
{
if (currentViewModel == value)
return;
currentViewModelInMainViewModel = value;
RaisePropertyChanged("CurrentViewModelInMainViewModel");
}
}
public MainWindowViewModel()
{
ViewModelSelector ViewModelSelector = new ViewModelSelector();
CurrentViewModelInMainViewModel = ViewModelSelector.CurrentViewModel;
}
}
}
The class ViewModelSelector:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProgramEditor.ViewModel
{
using GalaSoft.MvvmLight;
class ViewModelSelector : ViewModelBase
{
public ViewModelBase CurrentViewModel
{
get { return currentViewModel; }
set
{
if (currentViewModel == value)
return;
currentViewModel = value;
RaisePropertyChanged("CurrentViewModel");
}
}
private ViewModelBase currentViewModel;
public ViewModelSelector()
{
CurrentViewModel = new ViewModel1();
}
}
}
The dummy ViewModel1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProgramEditor.ViewModel
{
using GalaSoft.MvvmLight;
public class ViewModel1 : ViewModelBase
{
}
}
<DataTemplate DataType="{x:Type ViewModel:FirstViewModel}">
<TextBlock Text="There be dragons here." FontSize="50"/>
</DataTemplate>
My MainView.xaml:
<Window x:Class="ProgramEditor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:ProgramEditor.View"
xmlns:ViewModel="clr-namespace:ProgramEditor.ViewModel"
Title="MainWindow" Height="900" Width="1600">
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModel:ViewModel1}">
<TextBlock Text="There be dragons here." FontSize="50"/>
</DataTemplate>
</Window.Resources>
<StackPanel>
<!-- This works (shows up in main window): -->
<ContentControl Content="{Binding CurrentViewModelInMainViewModel}"/>
<!-- This does not work (does not show up in main window): -->
<!--<ContentControl Content="{Binding ViewModelSelector.CurrentViewModel}"/>-->
</StackPanel>
</Window>
The answer was a trivial programming error. I was overriding the ViewModelSelector property in the constructor of MainViewModel.cs here: ViewModelSelector ViewModelSelector = new ViewModelSelector();
After changing that line to ViewModelSelector = new ViewModelSelector(); it now works as expected.
I have a textblock in WPF which is bound to a property in my ViewModel class. On click of a button I wish to modify the property and expect the same to be reflected in my textblock. I want all these to be done purely using MVVM (MVVMLight). I am using MMVM light and VS 2012.
Challenges- On button click the changes are not being reflected. Though the program execution is going inside the property , changes are not being made.
Please Help !!
Program- View:
<Window x:Class="MvvmLight1_Trail.MainWindow"
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:ignore="http://www.ignore.com"
mc:Ignorable="d ignore"
Height="500"
Width="500"
Title="MVVM Light Application"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Grid x:Name="LayoutRoot">
<TextBlock FontSize="34"
Text="{Binding Path=MyText,UpdateSourceTrigger=Default, Mode=TwoWay}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap" />
<Button Width="100" Height="100" Command="{Binding PressCommand}" Margin="198.985,277.537,193.014,92.462" Content="Press Me"/>
</Grid>
View Model
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using MvvmLight1_Trail.Model;
using System.ComponentModel;
using System.Threading;
namespace MvvmLight1_Trail.ViewModel
{
public class MainViewModel : ViewModelBase
{
public RelayCommand PressCommand { get; private set; }
Thread t;
private string _welcomeTitle = string.Empty;
public string MyText
{
get
{
return _welcomeTitle;
}
set
{
if (_welcomeTitle == value)
{
return;
}
_welcomeTitle = value;
RaisePropertyChanged(MyText);
}
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
PressCommand = new RelayCommand(() => MyFunc());
myfunc();
}
private void MyFunc()
{
this.MyText = "Hi2";
}
private void myfunc()
{
this.MyText = "Hello";
this.MyText = "Hi";
}
}
}
Replace
RaisePropertyChanged(MyText);
to
RaisePropertyChanged("MyText");
PropertyChanged event should be raised on property name and not on property value.
Already answered by #Rohit Vats. You can also call RaisePropertyChanged like, RaisePropertyChanged( () => MyText) to ease renaming later.
Late to the game but:
in new C# 6 you can also use nameof like this:
RaisePropertyChanged(nameof(MyText))