Cant get twoWay Binding from Xaml to ObservableCollection Working - c#

Im attempting to bind a gridView to a ObservableCollection in a Windows Store App. My problem is I get the data but the set does not seem to work
public class ValveData : INotifyPropertyChanged
{
private string valveName;
private decimal waterMl;
private decimal waterEc;
private decimal waterPh;
public string ValveName
{
get { return this.valveName; }
set
{
this.valveName = value;
this.OnPropertyChanged("ValveName");
}
}
public decimal WaterMl
{
get { return this.waterMl; }
set
{
this.waterMl = value;
this.OnPropertyChanged("WaterMl");
}
}
public decimal WaterEc
{
get { return this.waterEc; }
set
{
this.waterEc = value;
this.OnPropertyChanged("WaterEc");
}
}
public decimal WaterPh
{
get { return this.waterPh; }
set
{
this.waterPh = value;
this.OnPropertyChanged("WaterPh");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class ValveDataCollection : ObservableCollection<ValveData>
{
public ValveDataCollection() : base()
{
Add(new ValveData { ValveName = "Valve 1", WaterMl = 100, WaterEc = 3, WaterPh = 5 });
Add(new ValveData { ValveName = "Valve 2" });
Add(new ValveData { ValveName = "Valve 3" });
Add(new ValveData { ValveName = "Valve 4" });
}
}
and this is my Xaml
<data:ValveDataCollection x:Key="ValvesData"/>
<GridView x:Name="gw1" Grid.Row="2" ItemsSource="{StaticResource ValvesData}">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding ValveName, Mode=TwoWay}"/>
<TextBox Text="{Binding WaterMl, Mode=TwoWay}"/>
<TextBox Text="{Binding WaterEc, Mode=TwoWay}"/>
<TextBox Text="{Binding WaterPh, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Im sure im missing something but I've been looking at this code for days and can't figure it out
The string looks like it works, meaning if i have 2 textboxes linked to the ValveName String the set the string and get the data but it looks like its not working for the decimals, they get the data on startup but if you modify it in the textbox it doesn't seem to affect the variable

The correct XAML should look like
<TextBox Text="{Binding ValveName, Mode=TwoWay}"/>
rather than
<TextBox Text="{Binding ValveName}, Mode=TwoWay"/>
Edit
On a side note:
This code isn't thread safe. Between this.PropertyChanged != null and this.PropertyChanged another thread could unsubscribe and PropertyChanged becomes null.
public void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Always use a local copy of the event handler!
public void OnPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
This one is thread now safe
For future readers: With C# 6.0 (Visual Studio 2015) you can also use the below version, which is shorter and thread safe, using the new "Null Propagation Operator" operator.
public void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

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(); }
}
}

Textblock binding text

I want to display the string _lunedi in a textbox, the string _lunedi is updated periodically using InitializeBoxes().
I have my class:
public event PropertyChangedEventHandler PropertyChanged;
private string _lunedi= "lunedi ";
public string lunedi
{
get { return this._lunedi; }
set
{
if (value != this._lunedi)
{
this._lunedi = value;
NotifyPropertyChanged("lunedi");
}
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
whit this method change the lunedi:
private void InitializeBoxes()
{
lunedi += todayPivot.Day;
}
xaml:
<Border>
<TextBlock Text="{Binding Path=lunedi, UpdateSourceTrigger=PropertyChanged}"></TextBlock>
</Border>
The problem is that the text of the textblock is empty.
Thank you.
Sounds like the binding is using one time try this instead
<Border>
<TextBlock Text="{Binding Path=lunedi, Mode=OneWay}"></TextBlock>

Bindings on a ContentControl do not update the data

I have the code:
<TextBox Width="200" Text="{Binding Value}"></TextBox>
Which works. However the "Value" can be different types. So if I have an bool I want to show a checkbox. I rewrote it as as follow, which kinda works:
<ContentControl Content="{Binding Value}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type sys:Boolean}">
<CheckBox IsChecked="{Binding Path=.}"></CheckBox>
</DataTemplate>
<DataTemplate DataType="{x:Type sys:Double}">
<TextBox Width="200" Text="{Binding Path=.}"></TextBox>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
But now the property isn't updated like before. I have tried setting Mode=Twoway, but it still do not work.
Edit
It worked perfectly fine when I only had the textbox, editing the text of the textbox updated the model. However when I tried doing this with the second code (ContentControl) it just doesn't work.
Code
I'm using Mvvm-light togheter with bindings. The "Value" is bound to an instance of Property
[JsonObject]
public class Property<T> : INotifyPropertyChanged
{
[JsonProperty]
public String name;
public Property(String name, T value)
{
this._value = value;
this.name = name;
}
[JsonIgnore]
public T Value {
get { return _value; }
set {
_value = value;
hot = true;
NotifyPropertyChanged("Value");
}
}
[JsonProperty(PropertyName = "value")]
private T _value;
[JsonIgnore]
public String Name { get { return name; } set { name = value; } }
[JsonProperty]
public bool hot = false;
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You should implement INotifyPropertyChanged interface in order to track property changes. I'm sure everything works fine then.
This works for me:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private object value;
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
DataContext = this;
}
public object Value
{
get { return value; }
set
{
this.value = value;
NotifyPropertyChanged("Value");
}
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Value = true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Silverlight ComboBox SelectedValue TwoWay Binding not working

I have used many ComboBoxes in my applications and all of them are working without any problem. But, I can't find the problem now. I have set SelectedValuePath to "Tag" property. But the property not updating after changing the ComboBox selected item. I have read other StackOverflow questions, but nontheless helped.
It is xaml:
xmlns:vms="clr-namespace:SilverlightApplication1"
<UserControl.DataContext>
<vms:MainViewModel />
</UserControl.DataContext>
<Grid x:Name="LayoutRoot" Background="White">
<ComboBox Width="100" VerticalAlignment="Center" FontFamily="Segoe UI"
Height="30" Margin="0,5,0,0" HorizontalAlignment="Left"
SelectedValue="{Binding SelectedDifStatusComparer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="Tag">
<ComboBox.Items>
<ComboBoxItem Tag="H" >High</ComboBoxItem>
<ComboBoxItem Tag="L" >Low</ComboBoxItem>
<ComboBoxItem Tag="E" >Equal</ComboBoxItem>
</ComboBox.Items>
</ComboBox>
</Grid>
And here is the ViewModel:
public class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _selectedDifStatusComparer = "";
private string SelectedDifStatusComparer
{
get { return _selectedDifStatusComparer; }
set
{
_selectedDifStatusComparer = value;
MessageBox.Show(_selectedDifStatusComparer);
OnPropertyChanged("SelectedDifStatusComparer");
}
}
public MainViewModel()
{
SelectedDifStatusComparer = "E"; // It is working, the MessageBox is apperaing
}
}
Your property is private. Change it to public and it should work.
public class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _selectedDifStatusComparer = "";
public string SelectedDifStatusComparer
{
get { return _selectedDifStatusComparer; }
set
{
_selectedDifStatusComparer = value;
MessageBox.Show(_selectedDifStatusComparer);
OnPropertyChanged("SelectedDifStatusComparer");
}
}
public MainViewModel()
{
SelectedDifStatusComparer = "E"; // It is working, the MessageBox is apperaing
}
}
Your property is private. Change it to public and it should work.

Binding drives me Crazy

Edit:
the XAML:
<TextBlock Text="{Binding Path=CurrentShows}" Grid.Row="1"/>
produces following Output:
SilverlightHelloWorld.Deserialize.schedule
the XAML:
<TextBlock Text="{Binding Path=CurrentShows.Today}" Grid.Row="1"/>
nor
<TextBlock Text="{Binding Path=CurrentShows.Today.Date}" Grid.Row="1"/>
produce any Error or ouput while being in debugmode.
Anysuggestions?
OldStatement:
I've got a quiet well complicated Example here,
the best will be, I am starting with my Code.
This is my Codebehind:
Mainpage.xaml.cs
schedule currentshows;
public schedule CurrentShows
{
protected set
{
if (currentshows != value)
{
currentshows = value;
OnPropertyChanged("CurrentShows");
}
}
get
{
return currentshows;
}
}
schedule.cs
[XmlRoot]
public class schedule : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
DayCollection today;
[XmlElement("DAY")]
public DayCollection Today
{
set
{
if (today != value)
{
today = value;
OnPropertyChanged("Today");
}
}
get
{
return today;
}
}
private void OnPropertyChanged(string p)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
DayCollection.cs
public class DayCollection : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
ObservableCollection<TimeCollection> timecol;
[XmlElement("time")]
public ObservableCollection<TimeCollection> TimeCol
{
set
{
if (timecol != value)
{
timecol = value;
OnPropertyChanged("TimeCol");
}
}
get
{
return timecol;
}
}
string date;
[XmlAttribute(AttributeName = "attr")]
public string Date
{
set
{
if (date != value)
{
date = value;
OnPropertyChanged("Date");
}
}
get
{
return date;
}
}
private void OnPropertyChanged(string p)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
I am trying to get the String-Property "Date" in my Xaml to Show-Up.
But I am just don't get any Solution.
I totally would appreciate any help here, Thanks in Advance !
I've copied your code into a project and it works if you use this line instead to set up the TextBlock's binding
<TextBlock Text="{Binding Today.Date}" Grid.Row="1"/>
but I cannot tell from your code how you are setting up the outer data binding. Here's what I included in the MainPage constructor
currentshows = new schedule();
currentshows.Today = new DayCollection();
currentshows.Today.Date = "hallo";
LayoutRoot.DataContext = currentshows;
where LayoutRoot is the parent of the TextBlock, i.e.
<Grid x:Name="LayoutRoot">
<TextBlock Text="{Binding Today.Date}"/>
</Grid>

Categories

Resources