WPF Data binding Label content - c#

I'm trying to create a simple WPF Application using data binding.
The code seems fine, but my view is not updating when I'm updating my property.
Here's my XAML:
<Window x:Class="Calculator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:calculator="clr-namespace:Calculator"
Title="MainWindow" Height="350" Width="525"
Name="MainWindowName">
<Grid>
<Label Name="MyLabel" Background="LightGray" FontSize="17pt" HorizontalContentAlignment="Right" Margin="10,10,10,0" VerticalAlignment="Top" Height="40"
Content="{Binding Path=CalculatorOutput, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</Window>
Here's my code-behind:
namespace Calculator
{
public partial class MainWindow
{
public MainWindow()
{
DataContext = new CalculatorViewModel();
InitializeComponent();
}
}
}
Here's my view-model
namespace Calculator
{
public class CalculatorViewModel : INotifyPropertyChanged
{
private String _calculatorOutput;
private String CalculatorOutput
{
set
{
_calculatorOutput = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I'm can't see what I am missing here?? o.O

CalculatorOutput has no getter. How should the View get the value? The Property has to be public as well.
public String CalculatorOutput
{
get { return _calculatorOutput; }
set
{
_calculatorOutput = value;
NotifyPropertyChanged();
}
}

Related

WPF Binding control with another class

i would like to know how to bind a textbox to the property of another class. I can bind a property defined in the same class than the DataContext. But not to a property defined in a subclass. When i click on the button, only the label1 is updated. I do not know how to inform the system that Label2 is linked to the property Class1.Label2
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string _Label1;
public string Label1
{
get { return _Label1; }
set
{
_Label1 = value;
OnPropertyChanged("Label1");
}
}
private Class1 objClass1;
public MainWindow()
{
InitializeComponent();
objClass1 = new Class1();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Label1 = "foo";
objClass1.Label2 = "bar";
}
}
The sub class object:
class Class1 : INotifyPropertyChanged
{
private string _Label2;
public string Label2
{
get { return _Label2; }
set
{
_Label2 = value;
OnPropertyChanged("Label2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
The xaml file :
<Window x:Class="WpfAppBinding2.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:WpfAppBinding2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Label Content="{Binding Path=Label1}" HorizontalAlignment="Left" Margin="240,117,0,0" VerticalAlignment="Top" Width="71"/>
<Label Content="{Binding Path=Class1.Label2}" HorizontalAlignment="Left" Margin="240,158,0,0" VerticalAlignment="Top" Width="71"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="276,49,0,0" VerticalAlignment="Top" Click="Button_Click"/>
</Grid>
Thank you for your help.

UWP Binding in Textbox works does not work in async method

I have a UWP Application. The viewModel and the Datacontext are set correctly, INotifiedPropertyChanged is implemented correctly, PropertyChanged is firing correctly, Binding Mode is set to OneWay but the Textbox is only updated if the property is changed in the constructor of the viewmodel. If it is changed in the async method loadJSONFromResources it doesn't work.
Here is my XAML:
<Page
x:Class="VokabelFileErstellen.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VokabelFileErstellen"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<local:ViewModel x:Name="viewModel"/>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" DataContext="{StaticResource ResourceKey=viewModel}">
<TextBlock Style="{StaticResource HeaderTextBlockStyle}" Margin="20,0,0,0" >
<Run Text="Anzahl Vokabeln: "/>
<Run Text="{Binding Count, Mode=OneWay}"/>
</TextBlock>
</Grid>
</Page>
This is my viewModel:
class ViewModel : INotifyPropertyChanged
{
private int count;
public List<Vokabel> Buecher { get; set; }
public int Count
{
get { return count; }
set
{
if (value != count)
{
count = value;
OnPropertyChanged("Count");
}
}
}
public ViewModel()
{
Count = 1;
}
public async void jsonLaden()
{
FileOpenPicker picker = new FileOpenPicker
{
SuggestedStartLocation = PickerLocationId.ComputerFolder
};
picker.FileTypeFilter.Add(".json");
IStorageFile file = await picker.PickSingleFileAsync();
loadJSONFromResources(file);
}
public async void loadJSONFromResources(IStorageFile file)
{
string json = await FileIO.ReadTextAsync(file);
Buecher = JsonConvert.DeserializeObject<List<Vokabel>>(json);
Count = Buecher.Count;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("propertyName"));
}
}
and this is my MainPage code behind:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
viewModel.jsonLaden();
}
}
just change
PropertyChanged(this, new PropertyChangedEventArgs("propertyName"));
with
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
it is workin', but the only notification UI gets is that property named "propertyName" has changed, intead of the name you are passing to OnPropertyChanged method

Change datatemplate of contentcontrol on change of datacontext property

I have a contentcontrol that is bound to an object (data property of DataContext in the example). Whenever the object referenced by data changes, I want to re-select the datatemplate. How can I do that?
<ContentControl Name="rootData" Content="{Binding data}"
ContentTemplateSelector="{StaticResource myTemplateSelector}"/>
In Case you are changing whole data type then your view should be as below, Only difference is removing key and using DataType for DataTemplate, this is called implicit data template
<Window x:Class="TextBindingFormatting.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TextBindingFormatting"
xmlns:viewModels="clr-namespace:TextBindingFormatting.ViewModels"
Title="MainWindow" Height="350" Width="555">
<Window.Resources>
<local:MyTemplateSelector x:Key="MyTemplateSelector"></local:MyTemplateSelector>
<DataTemplate DataType="{x:Type viewModels:Student}">
<StackPanel Orientation="Horizontal">
<Label>Id</Label>
<TextBlock Text="{Binding Id}"></TextBlock>
<Label>Name</Label>
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Parent}">
<StackPanel Orientation="Vertical">
<Label>Name</Label>
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<ContentControl Content="{Binding Data}" >
</ContentControl>
<Button Content="Change DataTemplate" Click="ButtonBase_OnClick"></Button>
</StackPanel>
</Grid>
code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel() {Data = new Student{Id = 1, Name = "Student"}};
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as MainWindowViewModel;
vm.Data = new Parent() {Name = "This is parent"};
}
}
I have two classes as below
public class Student : INotifyPropertyChanged
{
private string _name;
private int _id;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public string Name {
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public int Id
{
get { return _id; }
set
{
_id = value;
OnPropertyChanged("Id");
}
}
}
And another
public class Parent : INotifyPropertyChanged
{
private string _name;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
}
If you have same data type and different values for Data then you can use DataTemplate Selector as below, Otherwise just use DataType attribute of DataTemplate and you don't even need datatemplate selector.
Below is sample code to select template every time you change the data.
MainWindow.xaml
<Window x:Class="TextBindingFormatting.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TextBindingFormatting"
Title="MainWindow" Height="350" Width="555">
<Window.Resources>
<local:MyTemplateSelector x:Key="MyTemplateSelector"></local:MyTemplateSelector>
<DataTemplate x:Key="Template1">
<StackPanel Orientation="Horizontal">
<Label>Label 1</Label>
<Label>Label 2</Label>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="Template2">
<StackPanel Orientation="Vertical">
<Label>Label 1</Label>
<Label>Label 2</Label>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<ContentControl Content="{Binding Data}" ContentTemplateSelector="{StaticResource MyTemplateSelector}"></ContentControl>
<Button Content="Change DataTemplate" Click="ButtonBase_OnClick"></Button>
</StackPanel>
</Grid>
Below is the Code Behind, Ideally button click should be handled using command, but for quick example I have implemented in code behind just to trigger change of data.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel() {Data = "1"};
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as MainWindowViewModel;
vm.Data = "2";
}
}
Below is the ViewModel for MainWindow
namespace TextBindingFormatting.ViewModels
{
public class MainWindowViewModel : INotifyPropertyChanged
{
private string _data;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public string Data
{
get { return _data; }
set
{
_data = value;
OnPropertyChanged("Data");
}
}
}
}
DataTemplate Selector
namespace TextBindingFormatting
{
public class MyTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var element = container as FrameworkElement;
if (element == null || item == null)
return base.SelectTemplate(item, container);
if (item.ToString() == "1")
return element.FindResource("Template1") as DataTemplate;
if (item.ToString() == "2")
return element.FindResource("Template2") as DataTemplate;
return base.SelectTemplate(item, container);
}
}
}
Found a possible solution here from Rachel:
Change Data template dynamically
DataTemplateSelector wont trigger on PropertyChange but setting triggers does the job for me!

Label Binding does not work

I am trying to bind a label to an Object.Object.Property and I don't get it run.
Here is my code:
XAML
<Window x:Class="MyApp.MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MyWindow" Height="1120" Width="800">
<Grid Name="MyGrid">
<StackPanel Orientation="Horizontal">
<Label FontWeight="Bold" FontSize="40" Content="{Binding MyDataObject/AnotherSubObject/MyProperty}"/>
</StackPanel>
</Grid>
</Window>
And the Code:
public partial class MyWindow : Window
{
public MySubObject MyDataObject { get; set; }
public MyWindow(MySubObject object)
{
InitializeComponent();
this.MyDataObject = object; // Contains MyDataObject.AnotherObject.MyProperty
DataContext = this;
}
}
And the code for MySubObject object looks like this:
public class MySubObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
AnotherObject _AnotherObject;
public MySubObject()
{
this._AnotherObject = new AnotherObject();
this._AnotherObject.Property = "Some Value";
}
public AnotherObject AnotherObject
{
get { return _AnotherObject; }
set { _AnotherObject = value; OnPropertyChanged("AnotherObject"); }
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
I would be glad to get dome support for this case.
Use Dot(.) as binding property path separator not Forward slash(/)
<Label FontWeight="Bold" FontSize="40"
Content="{Binding MyDataObject.AnotherSubObject.MyProperty}"/>

How do I set the datacontext to a class for a usercontrol in XAML?

I have the following class which implements INotifyPropertyChanged
updateNotify.cs
public class updateNotify : INotifyPropertyChanged
{
private DateTime? previousUpdate;
private DateTime? nextUpdate;
public event PropertyChangedEventHandler PropertyChanged;
public updateNotify()
{
}
public updateNotify(DateTime? value)
{
this.previousUpdate = value;
}
public DateTime? GASpreviousUpdate
{
get { return previousUpdate; }
set
{
previousUpdate = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("GASpreviousUpdate");
}
}
public DateTime? GASnextUpdate
{
get { return nextUpdate; }
set
{
nextUpdate = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("GASnextUpdate");
}
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
MainWindow.xaml.cs
public partial class MainWindow
{
private updateNotify properties = new updateNotify();
'''
public void start_dispatcherTimer()
{
dispatcherTimer.Stop();
DateTime timeNow = DateTime.Now;
properties.GASpreviousUpdate = timeNow;
properties.GASnextUpdate = timeNow.AddMinutes((double)Properties.Settings.Default.GASInterval);
dispatcherTimer.Start();
}
}
then in XAML
<UserControl x:Class="ProjectXYZ.Content.MainData"
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:DesignWidth="300" Height="400" >
....
<StackPanel>
<Label Content="Previous Refresh" Target="{Binding ElementName=PreviousRefresh}"/>
<TextBox x:Name="PreviousRefresh" Width="140" Text="{Binding Path=GASpreviousUpdate, Mode=OneWay}"/>
</StackPanel>
<StackPanel>
<Label Content="Next Refresh" Target="{Binding ElementName=NextRefresh}"/>
<TextBox x:Name="NextRefresh" Width="140" Text="{Binding Path=GASnextUpdate, Mode=OneWay}"/>
</StackPanel>
</UserControl>
but the textboxes are not updating in the UI for Text="{Binding Path=GASpreviousUpdate, Mode=OneWay}" and Text="{Binding Path=GASnextUpdate, Mode=OneWay}"
I think I need to set the datacontext but not sure how to do this in the usercontrol XAML. Please can someone point me in the right direction?
try:
public partial class MainWindow
{
public MainWindow()
{
this.DataContext = this.properties; // <----
}
}
I wouldn't call the field properties

Categories