Bind label Content to string property - c#

I want to bind the content of a label to a local property called "Status".
Codesnipped:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var logFilePath = GetPathToAppDirPlusLocalPath("LogFiles/MainLog.txt");
MainLog = new Log(#logFilePath);
MainLog.Add("MainWindow initialized");
this.DataContext = this;
}
private string _Status = null;
public string Status
{
get
{
return _Status;
}
set
{
_Status = value;
NotifyPropertyChanged("Status"); //Call the method to set off the PropertyChanged event.
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged(string propertyName = "")
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
XAML:
<Border x:Name="brd_Status" Grid.Row="9" Grid.ColumnSpan="10"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
Background="Black" DataContext="Status">
<Label x:Name="lbl_Status" Content="{Binding Path=Status,UpdateSourceTrigger=PropertyChanged}"
Grid.Row="9" Grid.ColumnSpan="10"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
FontSize="16" Foreground="White" FontFamily="Asenine">
</Label>
</Border>
I also tried Content = {Binding Status...} but makes no difference.
The label is just "null", while the property "Status" is "abcd1234...".
I debugged it and but, I am not sure where to search for a failure...

The issue is that MainWindow is not implementing INotifyPropertyChanged so even though you have and are raising the appropriate event, the runtime hasn't registered for it.
Change your class definition to:
public partial class MainWindow : Window, INotifyPropertyChanged
Also consider using a proper view model (look up MVVM), puting INPC on a view object is very bad design, and note that an UpdateSourceTrigger on a Label is useless as Label controls cannot be changed in the UI.

Related

My UserControl's TextBlock binding doesn't update even once

I know this has been asked for many times. I read a lot of them and tried different ways but still could not get it to work.
The xaml code is a UserControl:
<Grid Name="middle">
<d:TextBlock Text="{x:Bind LayerNodeData.CleanName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Foreground="WhiteSmoke" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" RelativePanel.RightOf="visibleUI" DoubleTapped="OnEditNameBegin" />
</Grid>
I set both this.DataContext and the Grid's DataContext to the data instance.
c#
public ucLayerRow(ImageLayerNode data)
{
LayerNodeData = data;
DataContext = LayerNodeData;
this.InitializeComponent();
middle.DataContext = LayerNodeData;
LayerNodeData.NotifyPropertyChanged("CleanName"); // test if it work
RefreshUI();
}
Model class
public partial class ImageLayerNode : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
// PropertyChanged is always null.
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public string mCleanName = string.Empty;
public string CleanName {
get => mCleanName;
set { mCleanName = value; NotifyPropertyChanged();}
}
....
}
I tried add a breakpoint to the PropertyChanged and found that it is always null and thus never get called. I also tried changing the mode to OneWay, TwoWays but still nothing.
The textblock is away empty not even getting a value once.
The user control is added like this to the main page. Not sure if it is related.
var rowUI = new ucLayerRow(layerNode);
layerContainer.Children.Add(rowUI);
My UserControl's TextBlock binding doesn't update even once
During the testing, the problem looks that you use design time for usercontrol. <d:TextBlock/> please remove d: and make your usercontrol like the following.
Xaml
<Grid>
<TextBlock
VerticalAlignment="Center"
FontFamily="Arial"
FontSize="12"
Foreground="Red"
Text="{x:Bind LayerNodeData.CleanName, Mode=OneWay}" />
</Grid>
Code behind
public sealed partial class ucLayerRow : UserControl
{
public ucLayerRow(ImageLayerNode data)
{
this.InitializeComponent();
LayerNodeData = data;
}
public ImageLayerNode LayerNodeData { get; set; }
}
public partial class ImageLayerNode : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
// PropertyChanged is always null.
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
private string mCleanName = string.Empty;
public string CleanName
{
get => mCleanName;
set { mCleanName = value; NotifyPropertyChanged(); }
}
}

WPF data binding not working after Initialize

I'm having some problems with data binding. It seems that values update up until the point when the form displays, after which it has no interest in updating.
On my view I have a label.
<Label Background="{Binding info_bg}" Foreground="{Binding info_fg}" Margin="5" Grid.Row="0" FontFamily="Arial Rounded MT Bold" FontSize="24" Grid.Column="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" >
<Label.Content>
<AccessText TextWrapping="Wrap" Text="{Binding info}" TextAlignment="Center" VerticalAlignment="Center" />
</Label.Content>
</Label>
In the code behind
public Client()
{
_cvm = new ClientViewModel();
this.DataContext = _cvm;
InitializeComponent();
}
In the ClientViewModel class (extends a CommonBase class which has the INotifyPropertyChanged)
public class ClientViewModel : CommonBase
{
private string _info = "";
public string info
{
get
{
return _info;
}
set
{
_info = value;
NotifyPropertyChanged("info");
}
}
public ClientViewModel()
{
this._info = "TEST UPDATE";
}
When I run this, the label shows TEST UPDATE as expected. In my code behind, I created a Window_KeyUp event to push the keys pressed through to the ClientViewModel class by calling _cvm.ProcessKey(e.Key);
public void ProcessKey(string key)
{
this._info = key;
}
MessageBox.Show(Info); gives me the key I pushed, so I know it's getting through, but the View isn't updating.
CommonBase class in case I've messed up here.
public class CommonBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Thank you.
Do not set the field like this this._info = key;
Instead set the property this.info = key;
This will invoke the set of the property and the PropertyChanged event will be raised. That is what is being observed by the view so it will respond.
(And while you are at it, start the properties with an uppercase.)

What am I doing wrong in this binding of a dependency property in the code behind (of a view) to a property its viewmodel?

A couple of other posts seem to indicate that data can be shared between a View's code behind and viewmodel by binding the dependency property in the code behind and property in the viemodel. Also, I have read that the DP should be in the code behind when itself is being bound in a Main Window/User Control relationship.
The following is from the code behind (SetupUC)
public static readonly DependencyProperty UC1Property =
DependencyProperty.Register(
"UC1", typeof(string), typeof(SetupUC),
new FrameworkPropertyMetadata()
{
PropertyChangedCallback = OnUC1Changed,
BindsTwoWayByDefault = true
});
public string UC1
{
get { return (string)GetValue(UC1Property); }
set
{
SetValue(UC1Property, value);
}
}
public SetupUC()
{
InitializeComponent();
SetupViewModel svm = new SetupViewModel();
this.DataContext = svm;
Binding binding = new Binding("ViewModelStringProperty") { Source = svm, Mode = BindingMode.TwoWay };
BindingOperations.SetBinding(this, SetupUC.UC1Property, binding);
}
and the viewmodel (SetupViewModel)
private string _viewModelStringProperty;
public string ViewModelStringProperty
{
get { return _viewModelStringProperty; }
set
{
_viewModelStringProperty = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("ViewModelStringProperty"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
In debugging, UC1 seems to always be updated correctly from the Main Window as its changes are reflected in the user control view. However, in the viewmodel, ViewModelStringProperty does not ever seem to be updated - it's always null. Full disclosure(!), the following is how UC1 is bound in the user control XAML
<TextBox x:Name="tbx1" HorizontalAlignment="Left" Height="23" Margin="159,22,0,0" TextWrapping="Wrap" Text="{Binding UC1, ElementName=root}" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.017,0.304"/>
Again, this part seems to be fine, it's getting data to ViewModelStringProperty in the viewmodel that is not.
To ensure your changes in your TextBox are immediately pushed to the DependencyProperty and subsequently the view-model, ensure you have UpdateSourceTrigger=PropertyChanged on your TextBox.Text binding, i.e.:
Text="{Binding UC1, ElementName=root, UpdateSourceTrigger=PropertyChanged}"
With this, my example worked perfectly fine.
If this doesn't help, I suggest adding two additional TextBlocks, one bound to the UC1 and one bound to ViewModelStringProperty, this will make it easier to tell which are getting updated correctly, e.g.:
<StackPanel>
<TextBox Text="{Binding UC1, ElementName=Root, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding UC1, ElementName=Root}" />
<TextBlock Text="{Binding ViewModelStringProperty}" />
</StackPanel>

Binding textblock text to property on load

I'm trying to display the number of records retrieved by the query after the window loads. Here's what I have in my XAML:
<TextBlock Name="numRecordsAnalyzed_TAtab" TextWrapping="Wrap" Margin="12,0,0,4" Grid.RowSpan="2">
<Run Text="Records Found: " Foreground="{StaticResource Foreground}" FontSize="12"/>
<Run Text="{Binding Numrecords}" Foreground="Red" FontSize="12"/>
</TextBlock>
Here's my c#:
private int numOfrecords = 0;
public event PropertyChangedEventHandler PropertyChanged;
public string Numrecords
{
get { return Convert.ToString(numOfrecords); }
set
{
OnPropertyChanged("NumOfrecords");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
Then I add this to get the number of records and when I debug I see that the variable holds the number and everything but nothing is displayed in the window when the window launches:
numOfrecords = OpenTradesQuery.Count();
What am I missing?
You need to raise PropertyChanged event to notify GUI to update.
Declare property of type int, WPF will automaically call ToString() on your property, you need not to worry about that.
public int Numrecords
{
get { return numOfrecords; }
set
{
if(numOfrecords != value)
{
numOfrecords = value;
OnPropertyChanged("Numrecords");
}
}
}
Set the property:
Numrecords = penTradesQuery.Count();
You can set DataContext in code behind after InitializeComponent() in constructor of Window/UserControl:
DataContext = this;
Also, you can set it in XAML at root level like this:
<Window DataContext="{Binding RelativeSource={RelativeSource Self}}"/>

what's wrong with my databinding?

I've copied code from the blank panorama project and made some adjustments, but somewhere something ain't right.
I've got my textblock set up:
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding ElementName=CurrentPlaceNow, Path=Temperature}" />
My model looks like this:
public class CurrentPlaceNowModel : INotifyPropertyChanged
{
#region PropertyChanged()
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
private string _temperature;
public string Temperature
{
get
{
return _temperature;
}
set
{
if (value != _temperature)
{
_temperature = value;
NotifyPropertyChanged("Temperature");
}
}
}
}
And defined defined in the MainViewModel():
public CurrentPlaceNowModel CurrentPlaceNow = new CurrentPlaceNowModel();
Finally I've added a modifier to a buttonclick:
App.ViewModel.CurrentPlaceNow.Temperature = "foo";
Now, why isn't anything showing up in the textbox?
Your Binding should navigate through the ViewModel. Binding to an ElementName tries to look at another object in the Visual Tree.
Change your Binding to this:
<TextBlock
Grid.Column="0"
Grid.Row="0"
Text="{Binding CurrentPlaceNow.Temperature}" />
Verify your ViewModel's property is formatted properly:
private CurrentPlaceNowModel _CurrentPlaceNow = new CurrentPlaceNowModel();
public CurrentPlaceNowModel CurrentPlaceNow
{
get { return _CurrentPlaceNow; }
set
{
_CurrentPlaceNow = value;
NotifyPropertyChanged("CurrentPlaceNow");
}
}
As long as your View's DataContext is your MainViewModel, you are good to go.
You are using ElementName wrong. ElementName is when you want to bind to another XAML control, not to (view)model.
To bind to model, set instance of that model to DataContext property and bind only Path.

Categories

Resources