BindingList with INotifyPropertyChanged in WPF - c#

What is the proper way, for the UI to get notified, that property "Difference" has changed in the following code sample?
The property is read-only. The property's value must always be calculated based on the other properties.
MainWindow.xaml:
<Window x:Name="winCalcs" x:Class="BindingList.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:BindingList"
Title="Calculations" Height="350" Width="525">
<Window.Resources>
<m:OperationList x:Key="OperationData"/>
<CollectionViewSource x:Key="Operations"
Source="{StaticResource ResourceKey=OperationData}"/>
</Window.Resources>
<Grid>
<TabControl x:Name="tabsMain">
<TabItem x:Name="tab01" Header="Tab 1">
<DataGrid x:Name="dg01"
ItemsSource="{Binding
Source={StaticResource ResourceKey=Operations},
UpdateSourceTrigger=PropertyChanged}" />
</TabItem>
<TabItem x:Name="tab02" Header="Tab 2">
<DataGrid x:Name="dg02"
ItemsSource="{Binding
Source={StaticResource ResourceKey=Operations},
UpdateSourceTrigger=PropertyChanged}" />
</TabItem>
</TabControl>
</Grid>
</Window>
Operation.cs:
namespace BindingList
{
class Operation : INotifyPropertyChanged
{
private float _minuend;
private float _subtrahend;
public float Minuend
{
get
{
return this._minuend;
}
set
{
if (this._minuend == value) return;
this._minuend = value;
this.NotifyPropertyChanged("Minuend");
}
}
public float Subtrahend
{
get
{
return this._subtrahend;
}
set
{
if (this._subtrahend == value) return;
this._subtrahend = value;
this.NotifyPropertyChanged("Subtrahend");
}
}
public float Difference
{
get
{
return Minuend - Subtrahend;
}
private set {}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string p)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}
OperationList.cs:
namespace BindingList
{
class OperationList : BindingList<Operation>
{
public OperationList()
{
Add(new Operation());
}
}
}

Difference changes when Minuend or Subtrahend changes. That means you need to notify changed for Difference within the set of Minuend or Subtrahend.
There is no need for property setter for Difference.
On a side note, there is no need for using this everywhere
public float Minuend
{
get
{
return _minuend;
}
set
{
if (_minuend == value) return;
_minuend = value;
NotifyPropertyChanged("Minuend");
NotifyPropertyChanged("Difference");
}
}
public float Subtrahend
{
get
{
return _subtrahend;
}
set
{
if (_subtrahend == value) return;
_subtrahend = value;
NotifyPropertyChanged("Subtrahend");
NotifyPropertyChanged("Difference");
}
}
public float Difference
{
get
{
return Minuend - Subtrahend;
}
}

In these situations I typically set the property explicitly and and raise the PropertyChanged event.
namespace BindingList
{
class Operation : INotifyPropertyChanged
{
private float _minuend;
private float _subtrahend;
private float _difference;
public float Minuend
{
get
{
return this._minuend;
}
set
{
if (this._minuend == value)
return;
this._minuend = value;
this.NotifyPropertyChanged("Minuend");
this.UpdateDifference();
}
}
public float Subtrahend
{
get
{
return this._subtrahend;
}
set
{
if (this._subtrahend == value)
return;
this._subtrahend = value;
this.NotifyPropertyChanged("Subtrahend");
this.UpdateDifference();
}
}
private void UpdateDifference()
{
this.Difference = this.Minuend - this.Subtrahend;
}
public float Difference
{
get
{
return this._difference
}
private set
{
if (this._difference == value)
return;
this._difference = value;
this.NotifyPropertyChanged("Difference");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string p)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}

Related

Find and select row in XamDataGrid C#

How can I search for a row by a column and later select that row in a XamDataGrid.
I've tried iterating over the DataSource, but the type of the elements isn't very helpful, it has only a HasData bool property exposed.
Try to use XamDataGrid.FieldLayouts.DataPresenter.Records collection and check for the required cell. When the record is found it can be selected by setting record.IsSelected = true;
Something like that:
using System;
using System.Windows;
using System.Windows.Media;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Infragistics.Windows.DataPresenter;
namespace IGFindRow
{
public partial class MainWindow : Window
{
public MainWindow()
{
_cars = Cars;
InitializeComponent();
}
#region Code fragment from samples provided by Infragistics
public ObservableCollection<Car> _cars = null;
public ObservableCollection<Car> Cars
{
get
{
if (this._cars == null)
{
this._cars = new ObservableCollection<Car>();
this._cars.Add(new Car("Dodge", "Ram", Colors.Blue, 22050.00, 153));
this._cars.Add(new Car("Ford", "Explorer", Colors.Green, 27175.00, 96));
this._cars.Add(new Car("BMW", "Z4", Colors.Silver, 35600.00, 42));
this._cars.Add(new Car("Toyota", "Camry", Colors.Black, 20790.99, 131));
}
return _cars;
}
}
public class Car : INotifyPropertyChanged
{
string m_make;
string m_model;
Color m_color;
double m_baseprice;
int m_milage;
public Car(string make, string model, Color color, double baseprice, int milage)
{
this.Make = make;
this.Model = model;
this.Color = color;
this.BasePrice = baseprice;
this.Milage = milage;
}
public string Make
{
get { return m_make; }
set
{
if (m_make != value)
{
m_make = value;
NotifyPropertyChanged("Make");
}
}
}
public string Model
{
get { return m_model; }
set
{
if (m_model != value)
{
m_model = value;
NotifyPropertyChanged("Model");
}
}
}
public Color Color
{
get { return m_color; }
set
{
if (m_color != value)
{
m_color = value;
NotifyPropertyChanged("Color");
}
}
}
public double BasePrice
{
get { return m_baseprice; }
set
{
if (m_baseprice != value)
{
m_baseprice = value;
NotifyPropertyChanged("BasePrice");
}
}
}
public int Milage
{
get { return m_milage; }
set
{
if (m_milage != value)
{
m_milage = value;
NotifyPropertyChanged("Milage");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
}
}
#endregion
private void Search_Click(object sender, RoutedEventArgs e)
{
// Enumerate records
foreach (var it in dataGrid.FieldLayouts.DataPresenter.Records)
{
if (it is DataRecord record)
{
// Check the current column value
if (record.Cells["Make"].Value.ToString().ToUpper() == Maker.Text.ToUpper())
{
record.IsSelected = true;
break;
}
}
}
}
}
}
The XAML:
<Window x:Class="IGFindRow.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:ig="http://infragistics.com/DataPresenter"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
Name="dgTest">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="5,5,5,5">
<Label Name="ColumnName" Padding="5,5,0,5">Maker:</Label>
<TextBox Name="Maker" Padding="5,5,5,5" Margin="3,0,20,0">Ford</TextBox>
<Button Name="Search" Padding="5,5,5,5" Click="Search_Click">Press to search</Button>
</StackPanel>
<ig:XamDataGrid x:Name="dataGrid" Grid.Row="1"
IsGroupByAreaExpanded="False"
GroupByAreaLocation="None"
Theme="Generic"
DataSource="{Binding ElementName=dgTest, Path=Cars}">
<ig:XamDataGrid.FieldLayoutSettings>
<ig:FieldLayoutSettings SelectionTypeRecord="Single" />
</ig:XamDataGrid.FieldLayoutSettings>
<ig:XamDataGrid.ViewSettings>
<ig:GridViewSettings/>
</ig:XamDataGrid.ViewSettings>
<ig:XamDataGrid.FieldSettings>
<ig:FieldSettings CellClickAction="SelectRecord" AllowRecordFiltering="True"/>
</ig:XamDataGrid.FieldSettings>
</ig:XamDataGrid>
</Grid>
</Window>

How to detect that entire binded ViewModel has changed?

I have a simple viewmodel class which contains three properties.
public class ColorViewModel : INotifyPropertyChanged
{
private int red;
public int Red
{
get { return red; }
set
{
if (red != value)
{
red = value;
RaisePropertyChanged("Red");
}
}
}
private int green;
public int Green
{
get { return green; }
set
{
if (green != value)
{
green = value;
RaisePropertyChanged("Green");
}
}
}
private int blue;
public int Blue
{
get { return blue; }
set
{
if (blue!= value)
{
blue = value;
RaisePropertyChanged("Blue");
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
Now I want to pass entire model to a given converter in order to create a color for RGB values.
<Rectangle Grid.Row="4" Grid.Column="1" HorizontalAlignment="Center" Height="120" Width="120"
Fill="{Binding Model, Converter={StaticResource intToBrushValueConverter}}"/>
where Model is one instance of my ColorViewModel.
The problem is that intToBrushValueConverter converter is trigger only once, when the program started. With the other words, the converter is not fired when Model is changed.
Then when one property of ColorViewModel is changed, the PropertyChanged is working, but initToBrushValueConverter converter it's not hitting.
There is one method to fix that ?
I'm searching for one solution without using MultiBinding or CommandParameter.
Thanks in advance.
Hook property changed event to parent viewmodel and in fire property changed event whenever property changes on Color property.
public class ParentViewModel : INotifyPropertyChanged
{
private ColorViewModel color;
public ColorViewModel Color
{
get { return color; }
set
{
if (color != value)
{
if (color != null)
color.PropertyChanged -= this.ChildPropertyChanged;
color = value;
if (color != null)
color.PropertyChanged += this.ChildPropertyChanged;
RaisePropertyChanged("Color");
}
}
}
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(Color == sender)
{
RaisePropertyChanged("Color");
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
UPDATE:
Full working solution below.
MainWindows.xaml.cs
using System;
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Random random = new Random();
private ParentViewModel model;
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.model = new ParentViewModel();
this.model.Color = new ColorViewModel();
}
public ParentViewModel Model
{
get { return model; }
set
{
model = value;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.model.Color.Blue = (byte)random.Next(0, 255);
this.model.Color.Green = (byte)random.Next(0, 255);
this.model.Color.Red = (byte)random.Next(0, 255);
}
}
}
MainWindow.xaml
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:IntToBrushConverter x:Key="intToBrushConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Rectangle HorizontalAlignment="Center" Height="120" Width="120" Fill="{Binding Model.Color, Converter={StaticResource intToBrushConverter}, FallbackValue=Black}"/>
<Button Grid.Row="1" Content="Click me!" Click="Button_Click" />
</Grid>
</Window>
IntToBrushConverter.cs
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace WpfApp1
{
public class IntToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is ColorViewModel)
{
var color = value as ColorViewModel;
return new SolidColorBrush(Color.FromRgb(color.Red, color.Green, color.Blue));
}
throw new NotSupportedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
ParentViewModel.cs
using System.ComponentModel;
namespace WpfApp1
{
public class ParentViewModel : INotifyPropertyChanged
{
private ColorViewModel color;
public ColorViewModel Color
{
get { return color; }
set
{
if (color != value)
{
if (color != null)
color.PropertyChanged -= this.ChildPropertyChanged;
color = value;
if (color != null)
color.PropertyChanged += this.ChildPropertyChanged;
RaisePropertyChanged("Color");
}
}
}
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (Color == sender)
{
RaisePropertyChanged("Color");
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
ColorViewModel.cs
using System.ComponentModel;
namespace WpfApp1
{
public class ColorViewModel : INotifyPropertyChanged
{
private byte red;
public byte Red
{
get { return red; }
set
{
if (red != value)
{
red = value;
RaisePropertyChanged("Red");
}
}
}
private byte green;
public byte Green
{
get { return green; }
set
{
if (green != value)
{
green = value;
RaisePropertyChanged("Green");
}
}
}
private byte blue;
public byte Blue
{
get { return blue; }
set
{
if (blue != value)
{
blue = value;
RaisePropertyChanged("Blue");
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
App.xaml and App.xaml.cs are standard as generated by template.
Output
Hope it helps!
The problem is that the Rectangle listens only to PropertyChanged events for the Model and not for the three color properties.
Try raising an event for the Model itself using RaisePropertyChanged("Model"); or RaisePropertyChanged(null);.

WPF Newbie: updating textbox value

I bind a class which derived from INotifyPropertyChange to a Datacontext.
after some interaction, a value will be calculated and output property will be updated.
My problem is that the result textbox didn't update at all.
public partial class setraSubWpfTolerance : UserControl
{
public setraFit objSource = new setraFit();
public setraSubWpfTolerance()
{
InitializeComponent();
this.DataContext = objSource;
}
}
And the class:
public class setraFit : INotifyPropertyChanged
{
private readonly CollectionView _BoreSystems;
public CollectionView BoreSystems
{
get { return _BoreSystems; }
}
private decimal? _MaxBoreDimension;
public decimal? MaxBoreDimension
{
get { return _MaxBoreDimension; }
set
{
if (_MaxBoreDimension == value) return;
_MaxBoreDimension = value;
onPropertyChanged("MaxBoreDimension");
}
}
private string _BoreSystem;
public string BoreSystem
{
get { return _BoreSystem; }
set
{
if (_BoreSystem == value) return;
_BoreSystem = value;
calcBoreDimension();
onPropertyChanged("BoreSystem");
}
}
public setraFit()
{
IList<string> listBore = setraStaticTolerance.getBoreList();
_BoreSystems = new CollectionView(listBore);
}
public event PropertyChangedEventHandler PropertyChanged;
private void onPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private void calcBoreDimension()
{
_MaxBoreDimension = (decimal)100.035;
}
}
Last but not least the XAML
<UserControl x:Class="SetraSubForms.setraSubWpfTolerance"
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="450" d:DesignWidth="375">
<Grid>
<ComboBox Height="23" HorizontalAlignment="Left" Margin="194,10,0,0" Name="BoreSystemComboBox" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Path=BoreSystems}"
SelectedValue="{Binding Path=BoreSystem}"/>
<TextBox HorizontalAlignment="Left" Margin="194,67,0,37" Name="MaxDimBoreTextBox" Width="120" IsReadOnly="False"
Text="{Binding Path=MaxBoreDimension, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</Grid>
</UserControl>
I expected to receive the dummy value of 100.035 after changing the combobox but the textbox did not update. If i run step by step i can see the "MaxBoreDimension" property of setraFit is changed.
What did i do wrong?
Thanks in advance for your help
sittingDuck
Your method is updating the private value, not the Property:
private void calcBoreDimension()
{
_MaxBoreDimension = (decimal)100.035;
}
Change to
private void calcBoreDimension()
{
MaxBoreDimension = (decimal)100.035;
}
You're doing the same thing in the constructor, which is causing your calcBoreDimension method to not run:
public setraFit()
{
IList<string> listBore = setraStaticTolerance.getBoreList();
_BoreSystems = new CollectionView(listBore);
}
should be
public setraFit()
{
IList<string> listBore = setraStaticTolerance.getBoreList();
BoreSystems = new CollectionView(listBore); //this line!
}
When you create properties that point to private fields, you should almost never have to set the private field anywhere other than the property. This is why properties exist- so that whenever you get or set them, you will run the code in the get and set blocks instead of just retrieving the current value.
SOLVED!
The key is to initate the PropertyChanged event for the "MaxBoreDimension"
public decimal? NominalDimension
{
get { return _NominalDimension; }
set
{
if (_NominalDimension == value) return;
_NominalDimension = value;
calcBoreDimension();
onPropertyChanged("NominalDimension");
onPropertyChanged("MaxBoreDimension");
}
}
Thanks DLeh for the contribution.

WP8 observablecollection item updates not reflected in view

I have the following XAML for a list of data items:
<phone:LongListSelector x:Name="Port_SummaryList" ItemsSource="{Binding PortList}" ItemTemplate="{StaticResource PortfolioDataTemplate}"/>
The template is defined as this:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="PortfolioDataTemplate">
<Grid d:DesignHeight="91.5" d:DesignWidth="439.875" Height="82">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="31*"/>
<ColumnDefinition Width="19*"/>
<ColumnDefinition Width="19*"/>
<ColumnDefinition Width="19*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15*"/>
<RowDefinition Height="15*"/>
<RowDefinition Height="15*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="PortfolioName" HorizontalAlignment="Left" Height="92" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top" Width="155" Grid.RowSpan="2" Margin="0,0,0,-10"/>
<TextBlock x:Name="NAV" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Height="31" TextWrapping="Wrap" Text="{Binding NAV, StringFormat='{}{0:C}'}" VerticalAlignment="Top" Width="95" Margin="0,-1,0,0"/>
<TextBlock x:Name="CostBasis" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left" Height="30" TextWrapping="Wrap" Text="{Binding Cost,StringFormat='{}{0:C}'}" VerticalAlignment="Top" Width="95" />
</Grid>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
and in my ViewModel I have this:
private TrulyObservableCollection<PortfolioModel> _PortList;
public TrulyObservableCollection<PortfolioModel> PortList
{
get { return _PortList; }
set
{
_PortList = value;
_PortList.CollectionChanged += _PortList_CollectionChanged;
RaisePropertyChanged("PortList");
}
}
void _PortList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
RaisePropertyChanged("PortList");
}
The class "TrulyObservableCollection<>" is from this SO post.
The class "PortfolioModel" is defined as this:
public class PortfolioModel : INotifyPropertyChanged
{
public string Name { get; set; }
public DateTime Created { get; set; }
public int Id { get; set; }
public TrulyObservableCollection<CashModel> Cashflow;
public TrulyObservableCollection<HoldingModel> Positions;
public float Cost
{
get
{
float total_cost = 0.0f;
foreach (HoldingModel holding in Positions)
{
total_cost += holding.Share * holding.CostBasis;
}
return total_cost;
}
private set { ;}
}
//Numbers that are calculated with other variables, listed here for databinding purposes
public float NAV
{
get
{
float acc = 0.0f;
foreach (HoldingModel hm in Positions)
{
acc += hm.CurrentPrice * hm.Share;
}
foreach (CashModel cm in Cashflow)
{
acc += cm.Amount;
}
return acc;
}
set { ;}
}
public float DailyPercent { get; set; }
public float OverallPercent { get; set; }
public PortfolioModel()
{
Cashflow = new TrulyObservableCollection<CashModel>();
Cashflow.CollectionChanged += Cashflow_CollectionChanged;
Positions = new TrulyObservableCollection<HoldingModel>();
Positions.CollectionChanged += Positions_CollectionChanged;
}
void Positions_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
NotifyPropertyChanged("Positions");
NotifyPropertyChanged("NAV");
}
void Cashflow_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
NotifyPropertyChanged("Cashflow");
NotifyPropertyChanged("NAV");
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The class "HoldingModel" is defined as this:
public class HoldingModel : INotifyPropertyChanged
{
private string _Ticker;
public string Ticker
{
get { return _Ticker; }
set { if (value != _Ticker) { _Ticker = value; NotifyPropertyChanged("Ticker"); } }
}
private string _CompanyName;
public string CompanyName
{
get { return _CompanyName; }
set { if (value != _CompanyName) { _CompanyName = value; NotifyPropertyChanged("CompanyName"); } }
}
private int _Share;
public int Share
{
get { return _Share; }
set { if (value != _Share) { _Share = value; NotifyPropertyChanged("Share"); } }
} //negative means short
public string LongShort
{
get { if (Share > 0) return "LONG"; else return "SHORT"; }
}
private float _Value;
public float Value
{
get { return _Value; }
set { if (value != _Value) { _Value = value; NotifyPropertyChanged("Value"); } }
}
public float Cost
{
get { return Share * CostBasis; }
set { ;}
}
private float _CostBasis;
public float CostBasis
{
get { return _CostBasis; }
set { if (value != _CostBasis) { _CostBasis = value; NotifyPropertyChanged("CostBasis"); } }
}
private float _RealizedGain;
public float RealizedGain
{
get { return _RealizedGain; }
set { _RealizedGain = value; NotifyPropertyChanged("RealizedGain"); }
}
private float _CurrentPrice;
public float CurrentPrice
{
get { return _CurrentPrice; }
set
{
_CurrentPrice = value;
NotifyPropertyChanged("CurrentPrice");
}
}
private float _CurrentChange;
public float CurrentChange
{
get { return _CurrentChange; }
set { _CurrentChange = value; NotifyPropertyChanged("CurrentChange"); }
}
ObservableCollection<TradeModel> Trades;
public HoldingModel()
{
Trades = new ObservableCollection<TradeModel>();
}
public void AddTrade(TradeModel trade)
{
//Order can't change, since RealizedGain relies on CostBasis and Share, CostBasis relies on Share
UpdateRealizedGain(trade);
UpdateCostBasis(trade);
Share += trade.Share;
trade.PropertyChanged += PropertyChanged;
Trades.Add(trade);
}
private void UpdateCostBasis(TradeModel trade)
{
if (trade.Share + Share == 0)
{
CostBasis = 0;
return;
}
float cost = CostBasis * Share;
cost += trade.Price * trade.Share;
CostBasis = cost / (Share + trade.Share);
}
private void UpdateRealizedGain(TradeModel trade)
{
if (trade.Share * Share > 0) return; //No realized gain on add-on
if (Math.Abs(trade.Share) > Math.Abs(Share))
{
RealizedGain += Share * (trade.Price - CostBasis);
}
else
{
RealizedGain += trade.Share * (trade.Price - CostBasis);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
//Debug.WriteLine("symbol_user got property {0} changed, bubbling up", propertyName);
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
What I wanted to do is that, every time I update the CurrentPrice property in HoldingModel, I want to see the NAV property in PortfolioModel change, and reflect that in the view. I tried all I can but still unable to achieve that. Is there anything that I'm missing? Any help is appreciated
I've also noticed some problems with LongListSelector and ObservableCollection. I've posted it here:
Long List Selector Observable Collection and Visual Tree - problems?
Please check in your project something like this: leave the Page with back button and the reenter the page with LLS - if it's correctly displayed that mean we have the same problems, and I think it's the problem with LLS and we have to wait for WP 8.1. I assume that LLS is not correctly Updated (VisualTree doesn't change), because when I use normal ListBox everything works perfect.
Try to use ListBox (as you don't have grouping):
<ListBox x:Name="Port_SummaryList" ItemsSource="{Binding PortList}" ItemTemplate="{StaticResource PortfolioDataTemplate}"/>
If you don't see changes you can try call (in my project that function didn't worj with LLS but with LisBox works fine):
Port_SummaryList.UpdateLayout();
Try explicitly specifying Mode=OneWay in the NAV binding.
Text="{Binding NAV, Mode=OneWay, StringFormat='{}{0:C}'}"
I just had a case where the Mode behaved like it was defaulting to the Mode=OneTime. After explicitly setting Mode=OneWay, my data changes started to display. The BindingMode Enumeration documentation here suggests Mode=OneWay is implied. Recent experience suggests that may not always be the case.

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