I'm making a basic program where a label updates when the user types in a text box. i'm trying to use data binding and INotifyPropertyChanged to work this out, so i don't want any workarounds. i used 2 buttons so i can actually see if they updated. here's my main class
namespace TestStringChangeFromAnotherClass
public partial class MainWindow : Window
{
textClass someTextClass = new textClass();
public MainWindow()
{
InitializeComponent();
}
public string someString1;
public string someString2;
private void btn1_Click(object sender, RoutedEventArgs e)
{
someTextClass.Text1 = tbx1.Text;
}
private void btn2_Click(object sender, RoutedEventArgs e)
{
someTextClass.Text2 = tbx1.Text;
}
}
here's the wpf for it
<Window x:Class="TestStringChangeFromAnotherClass.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="btn1" Content="Button" HorizontalAlignment="Left" Height="36" Margin="29,246,0,0" VerticalAlignment="Top" Width="108" Click="btn1_Click"/>
<Button x:Name="btn2" Content="Button" HorizontalAlignment="Left" Height="36" Margin="227,246,0,0" VerticalAlignment="Top" Width="124" Click="btn2_Click"/>
<Label x:Name="lbl1" Content="{Binding textClass.Text1}" HorizontalAlignment="Left" Height="37" Margin="74,32,0,0" VerticalAlignment="Top" Width="153"/>
<Label x:Name="lbl2" Content="{Binding textClass.Text2, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Height="38" Margin="74,90,0,0" VerticalAlignment="Top" Width="153"/>
<TextBox x:Name="tbx1" HorizontalAlignment="Left" Height="37" Margin="290,32,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="190"/>
</Grid>
as you can see, i've tried using UpdateSourceTrigger. i've also tried to use "someTestClass.Text1" instead of textClass.Test1, because that's how i defined it in the MainWindow. Here's my textClass
namespace TestStringChangeFromAnotherClass
public class textClass:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string text1;
public string Text1
{
get { return text1; }
set
{
text1 = value;
NotifyPropertyChanged("Text1");
}
}
private string text2;
public string Text2
{
get { return text2; }
set
{
text2 = value;
NotifyPropertyChanged("Text2");
}
}
protected void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
i can't figure out how to get wpf to look for the Test1 or Test2 strings in the separate class and update them when the strings change. i have a feeling the problem lies within DataContext, but i can't figure it out. i'd also rather not use DataContext within c#, only in WPF
UPDATE:
when i debug this, when it gets to NotifyPropertyChanged, PropertyChanged is evaluated as null. could that be the problem?
You bind DataContext to your Window which, as far as I can see, doesn't have textClass property. It has someTextClass field of textClass type. In order for your code to work your can change someTextClass to public property:
public textClass someTextClass { get; private set; }
initialize it in constructor:
public MainWindow()
{
someTextClass = new textClass();
InitializeComponent();
}
and then change binding to point to someTextClass property
<Label x:Name="lbl1" Content="{Binding someTextClass.Text1}" .../>
<Label x:Name="lbl2" Content="{Binding someTextClass.Text2}" .../>
You are binding to the MainWindow class itself as your DataContext, and trying to access the property called someTextClass that has the properties you want to bind to.
You are running into two problems:
1) Your XAML is trying to reference the desired object by it's type, not it's name. Not going to work. Your binding expressions should look like {Binding someTextClass.Text1} (note the difference in the first part of the path expression).
2) You can only bind to public things. Your field is not defined as public, and therefore is private. Even though the XAML should logically "be able to see" the property, as it's the same class, DataBinding will only work on public properties.
3) EDIT: You must also make this a property. WPF will not bind to fields.
In general, using Snoop will help diagnose silent binding errors.
Related
MainWindow.xaml
<Window x:Class="SDT.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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
xmlns:viewModels="clr-namespace:SDT.ViewModels"
Height="500" Width="700" WindowStyle="None" AllowsTransparency="False" ResizeMode="NoResize" Background="#FF2C2C2C"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.FontWeight="SemiBold">
<Window.DataContext>
<viewModels:UserViewModel />
</Window.DataContext>
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" Margin="308,90,0,0" TextWrapping="Wrap" Text = "{Binding Login}" VerticalAlignment="Top" Width="120"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="152,200,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<Button Content="Submit" Command="{Binding SubmitLoginDataCommand}" HorizontalAlignment="Left" Margin="567,259,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
MainWindows.cs
public partial class MainWindow : Window
{
UserViewModel userViewModel = new UserViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = userViewModel;
}
}
UserViewmodel
public class UserViewModel : INotifyPropertyChanged
{
private UserService userService = new UserService();
public string _firstName;
public string Login { get; set; }
public void SubmitLoginData(object loginData)
{
userService.CheckUserExist(Login);
}
public ICommand SubmitLoginDataCommand => new RelayCommand(SubmitLoginData, param => true);
public string FirstName
{
get { return _firstName; }
set
{
if (_firstName != value)
{
_firstName = value;
OnPropertyChanged("FirstName");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Hello.
What is wrong with FirstName binding?
Textbox shows nothing.
public string FirstName{} - FirstName here have value in debugging.
I tried without Window.DataContext and only with Text="{Binding FirstName}" but without success.
Login binding working fine.
You need to remove from MainWindow.xaml this part:
<Window.DataContext>
<viewModels:UserViewModel />
</Window.DataContext>
It becouse you have Twice DataContext,
In xaml and in cs so it is not know from where take the data.
I wanted to post a second answer to make a suggestion that I think you'll really like. We can have your OnPropertyChanged event automatically name the property, allowing you to just write "OnPropertyChanged()" to trigger the UI update.
To do this, we're going to use a property called "Caller Member Name" - which does what you'd think - provides the name of the object or property that's called the code!
To use this, we need to add a using statement to the top of your UserViewModel class:
using System.Runtime.CompilerServices;
Then, we will modify your OnPropertyChanged event to use the 'caller member name' unless you specify a specific name. It should look like this now:
private void OnPropertyChanged([CallerMemberName] String name = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
Now - we will update your property to use the simplified method:
public string FirstName
{
get { return _firstName; }
set
{
if (_firstName != value)
{
_firstName = value;
OnPropertyChanged();
}
}
}
Lastly - I've recently learned an alternative way for get/set's that i prefer. What you're doing is completely OK and there is no need to change it, but i'd suggest trying it to see how you like it :)
public string FirstName
{
get => _firstName;
set
{
if (_firstName == value) return;
_firstName = value;
OnPropertyChanged();
}
}
Reasons: I find it quicker to press == instead of !=, less brackets. If first name equals value it will simply return (exit). If not, it skips that return! I love that!
Let's test your binding! Let's add a text block to your form, and bind the FirstName property to it. Whatever you enter in the Textbox should be displayed in the textblock if your binding is working correctly.
Your MainWindow.xaml should look something like this:
<Window x:Class="SDT.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:viewModels="clr-namespace:Junk.cats"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" Margin="308,90,0,0" TextWrapping="Wrap" Text = "{Binding Login}" VerticalAlignment="Top" Width="120"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="152,200,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<Button Content="Submit" Command="{Binding SubmitLoginDataCommand}" HorizontalAlignment="Left" Margin="567,259,0,0" VerticalAlignment="Top" Width="75"/>
<TextBlock HorizontalAlignment="Left" Height="32" Margin="140,247,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="346">
<Run Text="First Name: "/>
<Run Text="{Binding Path=FirstName}"/>
</TextBlock>
</Grid>
I expect that this test will work, and you're going to see that you're not having an issue with your get/set properties and UI updates. I believe your issue is now with the 'instance' (copy) of the UserViewModel.
Let's pretend we're working with a printed document. When you use the = new UserService(); assignment, you're printing a fresh copy of our document. If we print a new document and give it to MainWindow.cs (Let's call it "Bob"), AND you then print a new copy in your userService code (Let's call this "Frank") - these are two independent instances / copies of the document.
We need to make this object once, and tell "Bob" and "Frank" to work with the same copy of the object. Don't worry, this is easier than you think, and you'll start getting used to it as you use it.
I'm going to use some STATIC fields to simplify your troubleshooting - you do not need to create a static instance to make this work, but you do need to make sure your instance of the shared class is available to whoever needs it.
Step 1 - Create a new class, let's call it 'Views'.
Step 2 - Make the class public static
Step 3 - Create a Public static userViewModel here:
public static class views
{
public static UserViewModel userViewModel = new UserViewModel();
}
Now - Let's change your MainWindow.cs to use the shared instance of this class:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = views.userViewModel;
}
}
The last thing you need to do - Make your external function work with the same copy of the 'userViewModel'! I don't have that code from you, so I'm pretending your function is called 'YourFunctioNToChangeTheName', and it's located in your 'UserService' class:
public class UserService
{
public void YourFunctionToChangeTheName()
{
views.userViewModel.FirstName = "FRANK";
}
}
The key thing to spot here is that you're not creating a new "UserViewModel" - you're re-using the same instance that the MainWindow.cs is bound to - so the UI is getting a 'property changed notification' now!
Remember, the UserViewModel (class) itself isn't static, we've created a shared / static instance of it that can be accessed from anywhere in your program. I suggested this approach so that you can learn the basics of an instance :)
Good luck!!
I have created a program that changes the text in a Label on the first window when you type in a TextBox on the second window. The idea is that I want to open a new window from my first window then on this new I want to type in a name and press a button to have that name be displayed on the first window. Am I making myself understood? Can anyone help me out? Thanks in advance!
The First Window(MainWindow)--
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
var createPlayerWindow = new CreatePlayerWindow();
DataContext = this;
createPlayerWindow.Show();
}
}
Xaml for MainWindow--
<Grid>
<Label x:Name="label2" Content="Name:" HorizontalAlignment="Left" Margin="10,63,0,0" VerticalAlignment="Top"/>
<Label x:Name="lblName" Content="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="90,63,0,0" VerticalAlignment="Top"/>
<Button x:Name="button" Content="Create Player" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="81" Click="button_Click"/>
</Grid>
The Second Window(CreatePlayerWindow)--
public partial class CreatePlayerWindow : Window
{
public CreatePlayerWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
string playerName = txbName.Text;
Player player = new Player(playerName);
this.DataContext = player;
}
}
Xaml for CreatePlayerWindow--
<Grid>
<Label x:Name="label" Content="Name :" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="txbName" HorizontalAlignment="Left" Height="23" Margin="63,12,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Button x:Name="button" Content="Create Player" HorizontalAlignment="Left" Margin="101,129,0,0" VerticalAlignment="Top" Width="88" Click="button_Click"/>
<Label x:Name="label1" Content="Class :" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>
<ComboBox x:Name="cmbClass" HorizontalAlignment="Left" Margin="63,45,0,0" VerticalAlignment="Top" Width="120"/>
</Grid>
The Model(Player)--
public class Player : ViewModelBase
{
private string _name;
public string Name
{
get
{
return this._name;
}
set
{
this._name = value;
OnPropertyChanged();
}
}
public Player(string name)
{
_name = name;
}
}
The ViewModel(ViewModelBase)--
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Have the main page's data context and the window's data context use the same instantiated VM which will have a Name property they both will use.
Then in xamls bind appropriately to the Name property on the VM which will adhere to the INotifyPropertyChange notification so that when it changes it will update the other item.
Don't forget that on the editing XAML the binding Mode should be TwoWay otherwise the user changes will not be seen.
Your MainWindow needs a ViewModel for its databinding. DataContext = this is useless here. So create a new class with a PlayerName property (with backing field), instanciate it in MainWindow constructor and set the main windows databinding to it. In the setter call OnPropertyChanged after setting the backingfield to value. Bind your label to the PlayerName property.
In your click event, you should create a viewmodel(player-)instance of your createplayerwindow and bind it to the createplayerwindow-instance's datacontext. add the missing databindings in your createplayerwindow to update your viewmodel (twoway). Replace the Show() method invocation in your button click event with ShowDialog(). After ShowDialog invokation call the new properties setter with the viewmodel.name value.
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 would like to understand how to correctly use MVVM and data binding when we are working with many properties.
<Window x:Class="WpfApplication1.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>
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="463" Text="{Binding OriginalText, UpdateSourceTrigger=PropertyChanged}" />
<Label Height="28" HorizontalAlignment="Left" Margin="12,242,0,0" Name="label1" VerticalAlignment="Top" Width="463" Content="{Binding ModifiedText}"/>
<CheckBox Content="Upper" Height="16" HorizontalAlignment="Left" Margin="12,41,0,0" Name="checkBox1" VerticalAlignment="Top" />
<CheckBox Content="Underline" Height="16" HorizontalAlignment="Left" Margin="12,63,0,0" Name="checkBox2" VerticalAlignment="Top" />
<CheckBox Content="Bold" Height="16" HorizontalAlignment="Left" Margin="12,85,0,0" Name="checkBox3" VerticalAlignment="Top" />
<CheckBox Content="Shadow" Height="16" HorizontalAlignment="Left" Margin="12,107,0,0" Name="checkBox4" VerticalAlignment="Top" />
<CheckBox Content="Red" Height="16" HorizontalAlignment="Left" Margin="12,129,0,0" Name="checkBox5" VerticalAlignment="Top" />
<CheckBox Content="Scary" Height="16" HorizontalAlignment="Left" Margin="12,151,0,0" Name="checkBox6" VerticalAlignment="Top" />
<CheckBox Content="Remove first letter" Height="16" HorizontalAlignment="Left" Margin="12,173,0,0" Name="checkBox7" VerticalAlignment="Top" />
<CheckBox Content="Remove last letter" Height="16" HorizontalAlignment="Left" Margin="12,195,0,0" Name="checkBox8" VerticalAlignment="Top" />
</Grid>
I have a OriginalText TextBox and a ModifiedText Label. When I check a box I would like to directly apply the modification without having to click a button. How should I do that?
In my ViewModel I created all the properties that are binded to the XAML CheckBox.
private string _originalText = string.Empty;
public string OriginalText
{
get { return _originalText; }
set
{
_originalText = value;
NotifyPropertyChanged("OriginalText");
}
}
private string _modifiedText;
public string ModifiedText
{
get { return _originalText; }
set
{
_originalText = value;
NotifyPropertyChanged("ModifiedText");
}
}
private bool upper;
public bool Upper
{
get { return upper; }
set
{
upper = value;
NotifyPropertyChanged("Upper");
// Should I notify something else here or call a refresh method?
}
}
private bool removeFirstLetter;
public bool RemoveFirstLetter
{
get { return removeFirstLetter; }
set
{
removeFirstLetter = value;
NotifyPropertyChanged("RemoveFirstLetter");
// Should I notify something else here or call a refresh method?
}
}
// ...
Then I created a Work method in the same ViewModel class at this moment. I ll move this method into the business later.
private void Work()
{
string result = _originalText;
if (Upper)
result = result.ToUpper();
if (removeFirstLetter)
result = result.Substring(1, result.Length);
// if ...
ModifiedText = result;
}
My question is when, where should I call the work method? Should I call it in each setter or getter? I dont like the idea. I do something wrong...
Thank you.
In your particular case, you should create a Boolean property using the INotifyPropertyChanged interface. Now bind this property to your "IsChecked" check box property. By calling your Work() method inside the setter, every time the check box is "ticked" the setter will trigger each time.
The answer to your question is very simple: Use Commands.
Commands are MVVM's way to realize the binding to a method in your ViewModel. The implementation of Commands follows a very standard pattern. You will find plenty of information over the Internet here is just a short sketch:
Commands implemented in your ViewModel have to be of type ICommand and every Command has to come along with to methods in your code one responsible for executing the actual method and the other one for checking if the execution is currently possible.
These methods have to be named CanExecute and Execute respectively. It is commonly the case to facilitate the use of several Commands with a small helping class called DelegateCommand which provides delegates for the previously mentioned methods.
Take this class as it is without any modifications:
public class DelegateCommand<T> : ICommand {
private Predicate<T> canExecute;
private Action<T> execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand (Predicate<T> canExecute, Action<T> execute) {
this.canExecute = canExecute;
this.execute = execute;
}
public bool CanExecute (object param) {
return canExecute((T)param);
}
public void Execute (object param) {
execute((T)param);
}
public void CanExecuteChangedRaised () {
CanExecuteChanged(this, new EventArgs());
}
}
Then your Command declarations are of type DelegateCommand rather than of type ICommand. See the following example to illustrate and you will get the idea:
Supose you have a method foo() in your ViewModel you want to be called with a click to a button:
class ViewModel {
// ...
public DelegateCommand<object> FooCommand { get; set; }
public ViewModel () {
FooCommand = new DelegateCommand<object>(CanExecuteFooCommand, ExecuteFooCommand);
}
public bool CanExecuteFooCommand (object param) {
return true;
}
public void ExecuteFooCommand (object param) {
foo();
}
// ...
}
Supposing you have set your ViewModel as the controls DataContext via it's DataContext property the only thing left to do is to bind the FooCommand to your button like this:
That's it!
APPENDIX (referring to comment):
In order to have some action take place without actually hitting the Button you would simply have to track any changed in the UI with your ViewModel and react accordingly - that's what MVVM is about: Track the data from the UI modify or process them and populate them back to the UI.
To react on a TextBox Text change create a corresponding string property in your ViewModel and track whether the new ioncoming value from the View is different to the current textBox text:
private string _text;
public string Text {
get { return _text; }
set {
// the text in the TextBox is about to change.
if (!_text.Equals(value))
{
doSomething();
}
_text = value;
FirePropertyChanged("Text");
}
}
For doing the same with your CheckBox you can apply ICommand as described above since CheckBox is derived from Button and is therefor offering the Command property.
How can I access the public variable which in Sample.xaml.cs file like asp.net <%=VariableName%>?
There are a few ways to do this.
Add your variable as a resource from codebehind:
myWindow.Resources.Add("myResourceKey", myVariable);
Then you can access it from XAML:
<TextBlock Text="{StaticResource myResourceKey}"/>
If you have to add it after the XAML gets parsed, you can use a DynamicResource above instead of StaticResource.
Make the variable a property of something in your XAML. Usually this works through the DataContext:
myWindow.DataContext = myVariable;
or
myWindow.MyProperty = myVariable;
After this, anything in your XAML can access it through a Binding:
<TextBlock Text="{Binding Path=PropertyOfMyVariable}"/>
or
<TextBlock Text="{Binding ElementName=myWindow, Path=MyProperty}"/>
For binding, if DataContext is not in use, you can simply add this to the constructor of the code behind:
this.DataContext = this;
Using this, every property in the code becomes accessible to binding:
<TextBlock Text="{Binding PropertyName}"/>
Another way is to just give a name to the root element of the XAML:
x:Name="root"
Since the XAML is compiled as a partial class of the code-behind, we can access every property by name:
<TextBlock Text="{Binding ElementName="root" Path=PropertyName}"/>
Note: access is only available to properties; not to fields. set; and get; or {Binding Mode = OneWay} are necessary. If OneWay binding is used, the underlying data should implement INotifyPropertyChanged.
For quick-and-dirty Windows in WPF, I prefer binding the DataContext of the Window to the window itself; this can all be done in XAML.
Window1.xaml
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource self}}"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBlock Text="{Binding Path=MyProperty1}" />
<TextBlock Text="{Binding Path=MyProperty2}" />
<Button Content="Set Property Values" Click="Button_Click" />
</StackPanel>
</Window>
Window1.xaml.cs
public partial class Window1 : Window
{
public static readonly DependencyProperty MyProperty2Property =
DependencyProperty.Register("MyProperty2", typeof(string), typeof(Window1), new UIPropertyMetadata(string.Empty));
public static readonly DependencyProperty MyProperty1Property =
DependencyProperty.Register("MyProperty1", typeof(string), typeof(Window1), new UIPropertyMetadata(string.Empty));
public Window1()
{
InitializeComponent();
}
public string MyProperty1
{
get { return (string)GetValue(MyProperty1Property); }
set { SetValue(MyProperty1Property, value); }
}
public string MyProperty2
{
get { return (string)GetValue(MyProperty2Property); }
set { SetValue(MyProperty2Property, value); }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Set MyProperty1 and 2
this.MyProperty1 = "Hello";
this.MyProperty2 = "World";
}
}
In the above example, note the binding used in the DataContext property on the Window, this says "Set your data context to yourself". The two text blocks are bound to MyProperty1 and MyProperty2, the event handler for the button will set these values, which will automatically propagate to the Text property of the two TextBlocks as the properties are Dependency Properties.
It is also worth noting that a 'Binding' can only be set on a DependencyProperty of a DependencyObject. If you want to set a non DependencyProperty (eg. a normal property) on an object in XAML, then you will have to use Robert's first method of using resources in the code behind.
myWindow.xaml
<Window
...
<TextBlock Text="{ Binding Path=testString }" />
</Window>
myWindow.xaml.cs
public partial class myWindow: Window
{
public string testString { get; set; } = "This is a test string";
public myWindow()
{
DataContext = this;
InitializeComponent();
}
}
Important
Set Datacontext
testString MUST be public
testString MUST be a property (have a get and set)