UWP: exception when setting a property just after setting another one - windows

I think I got a threading problem in my UWP app.
I want to do a very simple thing:
a UI with 2 numeric fields;
if a numeric value is typed in field1, I want field2 to be set with a ratio of field1 (example: field2 = ratio * field1).
I am using x:Bind and TextChanging events. For unknown reasons, I wasn't able in the XAML to "call" the TextChanging event without having an exception at startup. Therefore, I am using the Loaded event.
Here's my model class, simply called MyModel:
public class MyModel : INotifyPropertyChanged
{
private readonly uint r1 = 3;
private uint _field1;
public uint Field1
{
get { return this._field1; }
set
{
this.Set(ref this._field1, value);
if (value == 0)
{
Field2 = 0;
}
else
{
Field2 = value * r1;
}
}
}
private uint _field2;
public uint Field2
{
get { return this._field2; }
set
{
this.Set(ref this._field2, value);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisedPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
else
{
storage = value;
this.RaisedPropertyChanged(propertyName);
return true;
}
}
}
My ViewModel:
public class MyModelViewModel : INotifyPropertyChanged
{
public MyModel MyModel { get; set; }
public MyModelViewModel()
{
// Initialisation de notre page
this.MyModel = new MyModel()
{
Field1 = 0
};
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
my code behind (I'm filtering the input to avoid a cast exception):
public sealed partial class MainPage : Page
{
public MyModelViewModel ViewModel { get; set; } = new MyModelViewModel();
public MainPage()
{
this.InitializeComponent();
}
private void InitField1(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
field1.TextChanging += field1_TextChanging;
}
private void InitField2(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
field2.TextChanging += field2_TextChanging;
}
private void field1_TextChanging(TextBox sender, TextBoxTextChangingEventArgs args)
{
var error = errorTextBlock;
error.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
Regex regex = new Regex("[^0-9]+"); // All but numeric
if (regex.IsMatch(sender.Text))
{
error.Text = "Non numeric char";
error.Visibility = Windows.UI.Xaml.Visibility.Visible;
sender.Text = this.ViewModel.MyModel.Field1.ToString();
}
else
{
this.ViewModel.MyModel.Field1 = Convert.ToUInt32(sender.Text);
}
}
private void field2_TextChanging(TextBox sender, TextBoxTextChangingEventArgs args)
{
var error = errorTextBlock;
error.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
Regex regex = new Regex("[^0-9]+");
if (regex.IsMatch(sender.Text))
{
error.Text = "Non numeric char";
error.Visibility = Windows.UI.Xaml.Visibility.Visible;
sender.Text = this.ViewModel.MyModel.Field2.ToString();
}
else
{
this.ViewModel.MyModel.Field2 = Convert.ToUInt32(sender.Text);
}
}
}
Finally, my XAML:
<TextBlock Grid.Row="0" Grid.Column="0" x:Name="errorTextBlock" Text="" Visibility="Collapsed" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Field 1" />
<TextBox Grid.Row="1" Grid.Column="1" x:Name="field1" Text="{x:Bind ViewModel.MyModel.Field1, Mode=OneWay}" Loaded="InitField1" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Field 2" />
<TextBox Grid.Row="2" Grid.Column="1" x:Name="field2" Text="{x:Bind ViewModel.MyModel.Field2, Mode=OneWay}" Loaded="InitField2" />
At runtime, if I type a non numeric char in field1, the input is filtered, field1 returns to its previous value without the screen "blinking" (that's why I use the TextChanging event and not the TextChanged). Perfect! But if I type a numeric char, field1 is correctly updated (I can see that with breakpoint), but when field2 is set, I got a native exception when RaisedPropertyChanged is called:
I'm suspecting some kind of threading error, but I'm pretty new to this kind of development. Any idea? Thanks!

Updated to use a separate 'Model' class
Here's how you can create a text box that when a number (integer) is entered into it another text box shows the entered number multiplied by another number.
Here's the UI. Note the Mode used for each binding and the second textbox is readonly because that's just for display.
<StackPanel>
<TextBlock Text="Value 1" />
<TextBox Text="{x:Bind ViewModel.MyModel.Value1, Mode=TwoWay}" />
<TextBlock Text="Value 2" />
<TextBox Text="{x:Bind ViewModel.MyModel.Value2, Mode=OneWay}" IsReadOnly="True" />
</StackPanel>
On the page I declare my Model
public MyViewModel ViewModel { get; set; } = new MyViewModel();
My ViewModel is very simple
public class MyViewModel
{
public MyModel MyModel { get; set; } = new MyModel();
}
The Model class contains the logic
public class MyModel : INotifyPropertyChanged
{
private string _value1;
public string Value1
{
get { return _value1; }
set
{
if (_value1 != value)
{
_value1 = value;
// Cause the updated value to be displayed on the UI
OnPropertyChanged(nameof(Value1));
// Is the entered value a number (int)?
int numericValue;
if (int.TryParse(value, out numericValue))
{
// It's a number so set the other value
// multiplied by the ratio
Value2 = (numericValue * 3).ToString();
}
else
{
// A number wasn't entered so indicate this
Value2 = "NaN";
}
// Cause the updated value2 to be displayed
OnPropertyChanged(nameof(Value2));
}
}
}
// We can use the automatic property here as don't need any logic
// relating the getting or setting this property
public string Value2 { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
With the above, when a number is entered for Value1 then Value2 will show a number three times as much (because I've set the ratio of 3).
You may notice that if you try the above that the change doesn't happen immediately and Value2 is only updated when the focus leaves the Value1 text box. This is because, by default, the two-way binding is only updated when focus is lost. This can easily be changed though.
If instead of using the new x:Bind method of binding we use the traditional Binding method we can force the binding to be updated whenever we want. Say, when the text is changed.
Modify the TextBox declaration like this:
<TextBox Text="{Binding ViewModel.Value1, Mode=TwoWay}"
TextChanged="TextBox_OnTextChanged" />
Note that the binding syntax is different and we've added an event.
The handler of the event is
private void TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
{
var be = (sender as TextBox).GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
}
This forces the binding to update but there's another change we must make as well.
With the x:Bind syntax it tries to bind to the page. With the older Binding syntax it binds to the DataContext of the page. To make these the same, update the page constructor like this
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
}
Now the app will work again and Value2 will be updated after every key press in the Value1 text box.

Related

Xamarin: Bind picker selected item with FreshMvvM ViewModel

I'm creating a form where a product status needs to be selected with a dropdown menu.
I've created a picker for this. The data is loaded from a list in my ViewModel, but it doesn't get sent back.
I've tried the same using entry fields and that works fine. I just have no idea how to link the picker with the view model.
Here's my code.
Xaml
</Grid>
<Label Text="Current status" Style="{StaticResource MainLabel}"/>
<Label Style="{StaticResource MainLabel}" Text="{Binding ProductionStatus, Mode=TwoWay}"/>
<!-- gets send when saved-->
<Entry Style="{StaticResource MainEntry}" Text="{Binding ProductionStatus, Mode=TwoWay}" Keyboard="Text" />
<Label Text="Remark" Style="{StaticResource MainLabel} "/>
<!-- gets send when saved-->
<Entry Text="{Binding Remark}" Keyboard="Text" Style="{StaticResource MainEntry}"/>
<!-- Does not bind with anything.-->
<Picker x:Name="statusPicker" ItemsSource="{Binding ProductionOrderStatusName}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding ProductionStatusName}"/>
<Button Style="{StaticResource PrimaryButton}" Text="Save" Command="{Binding SaveCommand}"></Button>
Code-behind ViewModel
public ICommand SaveCommand
{
get
{
return new Command(ExecuteSaveCommand);
}
}
private async void ExecuteSaveCommand()
{
int statusId = FindProductionOrderStatusId(ProductionStatus); //the production status should be the result of the selected value in the picker
Guid id = _CurrentProductionOrder.Id;
string remark = Remark; // value from the remark entery in the xaml
await __productionOrderService.UpdateAsync(id, remark,statusId);
}
Properties
public ObservableCollection<ProductionOrderStatus> productionOrderStatusName;
public ObservableCollection<ProductionOrderStatus> ProductionOrderStatusName
{
get { return productionOrderStatusName; }
set
{
productionOrderStatusName = value;
}
}
public int amount;
public int Amount
{
get { return amount; }
set
{
amount = value;
}
}
public DateTime finishDate;
public DateTime FinishDate
{
get { return finishDate; }
set
{
finishDate = value;
}
}
public int ordernumber;
public int OrderNumber
{
get { return ordernumber; }
set
{
ordernumber = value;
}
}
public string remark;
public string Remark
{
get { return remark; }
set
{
remark = value;
}
}
public string productionStatus;
public string ProductionStatus
{
get
{
return productionStatus;
}
set
{
productionStatus = value;
}
}
private string materialNumber;
public string MaterialNumber
{
get { return materialNumber; }
set
{
materialNumber = value;
}
}
private string materialDescription;
public string MaterialDescription
{
get { return materialDescription; }
set
{
materialDescription = value;
}
}
Code behind loading my data
public OrderViewModel()
{
_productionOrderStepService = new MockingProductionOrderStepService();
_materialService = new MockingMaterialService();
__productionOrderService = new MockingProductionOrderService();
__productionOrderStatusService = new MockingProductionOrderStatusService();
_seederService = new Seeder(__productionOrderService, _productionOrderStepService, __productionOrderStatusService, _materialService);
_seederService.EnsureSeeded();
}
public override void Init(object initData)
{
_CurrentProductionOrder = initData as ProductionOrder;
LoadItemState();
base.Init(initData);
}
private void LoadItemState()
{
ObservableCollection<ProductionOrderStatus> ProductionStatusName = new ObservableCollection<ProductionOrderStatus>(__productionOrderStatusService.GetListAllAsync().Result);
this.ProductionOrderStatusName = ProductionStatusName;
this.materialDescription = FindMaterialDescription(_CurrentProductionOrder.MaterialId);
this.materialNumber = FindMaterialNumber(_CurrentProductionOrder.MaterialId);
this.productionStatus = FindProductionOrderStatus(_CurrentProductionOrder.StatusId);
this.remark = _CurrentProductionOrder.Remark;
this.amount=_CurrentProductionOrder.Amount;
this.finishDate = _CurrentProductionOrder.FinishDate;
this.ordernumber = _CurrentProductionOrder.OrderNumber;
}
Thx for the help!
you are making this more complicated than it needs to be
<Picker x:Name="statusPicker"
// this is the List of items X to display
ItemsSource="{Binding ProductionOrderStatusName}"
// this tells the picker which property of X to display to the user
ItemDisplayBinding="{Binding Name}"
// this is the specific X the user has selected
SelectedItem="{Binding SelectedStatus}" />
then in your VM
public ObservableCollection<ProductionOrderStatus> ProductionOrderStatusName { get; set; }
public ProductionOrderStatus SelectedStatus { get; set; }

BInding textColor in Xamarin

In a Xamarin app I’m trying to bind a textcolor with a property in Message model.
public class Message : INotifyPropertyChanged
{
public string text { get; set; }
public Color color { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
The task is, when I click on a label in a collectionview the text should change to Gray.
I can change the color in the ObservableCollection:
this.messages = new ObservableCollection();
(that’s works, and if I delete an entry in the ObservableCollection the screen updates)
But when I change the color in the message model, the screen doesn’t update.
I use MVVMhelpers, and I would like to use that to solve the problem, if possible.
best regards..
You could change the item color to gray when you click the item to triger the SelectionChanged event of CollectionView.
Xaml:
<CollectionView ItemsSource="{Binding messages}" SelectionMode="Single" SelectionChanged="CollectionView_SelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding text}" TextColor="{Binding color}"></Label>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Code behind:
public partial class Page2 : ContentPage
{
public ObservableCollection<Message> messages { get; set; }
public Page2()
{
InitializeComponent();
messages = new ObservableCollection<Message>()
{
new Message(){ text="A", color="Red"},
new Message(){ text="B", color="Red"},
new Message(){ text="C", color="Red"},
};
this.BindingContext = this;
}
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var previousItem = e.PreviousSelection.FirstOrDefault() as Message;
var currentItem = e.CurrentSelection.FirstOrDefault() as Message;
currentItem.color = "Gray";
if (previousItem!=null)
{
previousItem.color = "Red";
}
}
}
public class Message : INotifyPropertyChanged
{
private string _text;
public string text
{
get
{
return _text;
}
set
{
_text = value;
OnPropertyChanged("text");
}
}
private string _color;
public string color
{
get
{
return _color;
}
set
{
_color = value;
OnPropertyChanged("color");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
super, great thanks.
I should also add
<DataTemplate x:DataType="{x:Type Models:Message}">

How to Bind Xamarin Forms Checkbox isChecked to a dynamic bool variable?

I am newbie to xamarin forms. I have a Listview containing checkboxes. I bind the checkbox "isChecked" to one of the listview's itemsource bool property. the problem is, everytime i change the bool value where the checkbox is bind, checkbox appearance has'nt change. How can i achieve that kind of approach?enter image description here
[1]: https://i.stack.imgur.com/4KcT2.png
Hi #Weggie Villarante. Please try this.It's work for me
<ViewCell>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Orientation="Horizontal">
<Label Text="{Binding Title}" HorizontalOptions="StartAndExpand"></Label>
<CheckBox IsChecked="{Binding IsCheck}" HorizontalOptions="End" HeightRequest="50"></CheckBox>
</StackLayout>
</ViewCell>
NotificationModel.cs
public class NotificationModel : INotifyPropertyChanged
{
public string Message { get; set; }
public string Title { get; set; }
public bool _IsCheck = false;
public bool IsCheck
{
get
{
return _IsCheck;
}
set
{
_IsCheck = value;
this.OnPropertyChanged("IsCheck");
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
NotificationViewModel.cs
class NotificationViewModel : INotifyPropertyChanged
{
ObservableCollection<NotificationModel> _Items;
public ObservableCollection<NotificationModel> Items
{
get
{
return _Items;
}
set
{
_Items = value;
OnPropertyChanged();
}
}
public NotificationViewModel()
{
Items = new ObservableCollection<NotificationModel>();
AddItems();
}
void AddItems()
{
_Items.Add(new NotificationModel { Title = "Info", Message = "This is only information message please ignor this one." ,IsCheck = false});
_Items.Add(new NotificationModel { Title = "Alert", Message = "This is only Alert message please ignor this one." , IsCheck = false });
_Items.Add(new NotificationModel { Title = "Suggesstion", Message = "This is only Suggesstion message please ignor this one." , IsCheck = false});
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Validation fired but Red Border does not appear with User Control in Silverlight 4

I have created custom User Control which contain TextBox and PasswordBox. I bind TextBox to UserName and PassowrdBox also.
The UserName is defined in my LoginViewModel class with [Required] attribute. Now my cursor is leaving from TextBox without entering any value then UserName property fire property changeed notifcation (INotifyPropertyChanged),
but dose not mark my Textbox (which is inside the User Control) with Red border.
Following is code of my User Control.
RestrictedBox.xaml
<Grid x:Name="LayoutRoot" Background="Transparent" Margin="0" >
<TextBox x:Name="txtTextBox" HorizontalAlignment="Stretch" Height="25" />
<PasswordBox x:Name="txtPasswordBox" HorizontalAlignment="Stretch" Height="25" />
</Grid>
RestrictedBox.xaml.cs
public partial class RestrictedBox : UserControl
{
#region Properties
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(RestrictedBox), new PropertyMetadata("", ValueChanged));
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public bool Updateable
{
get { return (bool)GetValue(UpdateableProperty); }
set { SetValue(UpdateableProperty, value); }
}
public static readonly DependencyProperty UpdateableProperty = DependencyProperty.Register("Updateable", typeof(bool), typeof(RestrictedBox), new PropertyMetadata(UpdateableChanged));
private static void UpdateableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public bool Redactable
{
get { return (bool)GetValue(RedactableProperty); }
set { SetValue(RedactableProperty, value); }
}
public static readonly DependencyProperty RedactableProperty = DependencyProperty.Register("Redactable", typeof(bool), typeof(RestrictedBox), new PropertyMetadata(RedactableChanged));
private static void RedactableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
#endregion
#region Constructors
public RestrictedBox()
{
InitializeComponent();
txtTextBox.SetBinding(TextBox.TextProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay});
txtTextBox.SetBinding(TextBox.VisibilityProperty, new Binding("Redactable") { Source = this, Converter = new BoolToVisibilityConverterReverse() });
txtPasswordBox.SetBinding(PasswordBox.PasswordProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay });
txtPasswordBox.SetBinding(TextBox.VisibilityProperty, new Binding("Redactable") { Source = this, Converter = new BoolToVisibilityConverter() });
}
#endregion
}
Following is the code where i used my Custom User Control
LoginView.xaml
<Control:RestrictedBox x:Name="UserName" VerticalAlignment="Top" TabIndex="2" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" Height="40" Value="{Binding Path=LoginModelValue.UserName, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, ValidatesOnExceptions=True,
ValidatesOnDataErrors=True, NotifyOnValidationError=True}" Validatevalue:UpdateSourceTriggerHelper.UpdateSourceTrigger="True" Redactable="True" Updateable="True" />
LoginView.xaml.cs
[Export(typeof(LoginView))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class LoginView : UserControl, IPageTitle
{
#region Constuctors
public LoginView()
{
InitializeComponent();
}
[Import]
public LoginViewModel ViewModel
{
get {return this.DataContext as LoginViewModel;}
set { DataContext = value; }
}
#endregion
}
LoginViewModel.cs
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class LoginViewModel : INotifyPropertyChanged, IRegionMemberLifetime
{
private LoginModel _LoginModelValue;
public LoginModel LoginModelValue
{
get { return _LoginModelValue; }
set
{
_LoginModelValue = value;
OnPropertyChanged("LoginModelValue");
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
void LoginModelValue_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (LoginModelValue.IsValidObject())
{
LoginCommand.RaiseCanExecuteChanged();
IsEnabled = LoginModelValue.IsValidObject();
SetIncorrectLogin(!IsEnabled);
}
}
#endregion
}
Can anybody has idea why i am not getting Red Border surrounded with my TextBox which is inside my Custom User Control?
Any help, suggestions and comments would be highly appreciated!
Thanks,
Imdadhusen
As I've already said, the validation works only for one binding and is not inherited by consequent bindigns as in your case.
The easiest way would be to add the Required annotation directly to the Value property of your control and validate it once again:
[Required]
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(RestrictedBox), new PropertyMetadata("", ValueChanged));
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var rb = d as RestrictedBox;
Validator.ValidateProperty(rb.Value, new ValidationContext(rb, null, null) { MemberName = "Value" });
}
And add the ValidatesOnExceptions attribute to your bindings so that validation works:
txtTextBox.SetBinding(TextBox.TextProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay,
ValidatesOnExceptions = true });
//...
txtPasswordBox.SetBinding(PasswordBox.PasswordProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay,
ValidatesOnExceptions = true });
//...
Another way: to remove all the properties and bind the RestrictedBox control directly to your view model.
<TextBox x:Name="txtTextBox" HorizontalAlignment="Stretch" Height="25"
Text="{Binding LoginModelValue.UserName, Mode=TwoWay, ValidatesOnExceptions=True}" />
<PasswordBox x:Name="txtPasswordBox" HorizontalAlignment="Stretch" Height="25"
Password="{Binding LoginModelValue.UserName, Mode=TwoWay, ValidatesOnExceptions=True}" />
These solutions seem far from ideal, but actually the validation by data annotations is not good by design. I would recommend to use the INotifyDataErrorInfo interface.
Now i resolved issue using following code. I have replaced following line
txtTextBox.SetBinding(TextBox.VisibilityProperty, new Binding("Redactable") { Source = this, Converter = new BoolToVisibilityConverterReverse() });
with
this.MapBinding(RestrictedControl.ValueProperty, txtTextBox, TextBox.TextProperty);
and added following code. that's it.
namespace QSys.Library.Helpers
{
public static class FrameworkElementExtension
{
public static void MapBinding(this FrameworkElement element, DependencyProperty firstProperty, FrameworkElement targetElement, DependencyProperty secondProperty)
{
BindingExpression firstExpression = element.GetBindingExpression(firstProperty);
if (firstExpression != null && firstExpression.ParentBinding != null)
{
targetElement.SetBinding(secondProperty, firstExpression.ParentBinding);
}
}
}
}
I specially thanks to everybody how was looking for this. and i am also very thanksful Rakesh Gunijan (http://www.codeproject.com/Articles/293302/Silverlight-user-control-validation) how expain in very much clear.
Thanks,
Imdadhusen

"Refresh" Pivot Control with Mvvm-light toolkit for WP7

I have in my Xaml a pivot control :
<controls:Pivot ItemsSource="{Binding ObjectList}">
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock />
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Value1}" />
<TextBlock Text="{Binding Value2}" />
</StackPanel>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
My ViewModel is :
public class MyObject
{
public string Value1 { get; set; }
public string Value2 { get; set; }
}
public class MyViewModel : ViewModelBase
{
public const string ObjectListPropertyName = "ObjectList";
private ObservableCollection<MyObject> _objectList;
public ObservableCollection<MyObject> ObjectList
{
get
{
return _objectList;
}
private set
{
if (_objectList == value)
return;
_objectList = value;
RaisePropertyChanged(ObjectListPropertyName);
}
}
private DispatcherTimer timer;
public MyViewModel()
{
ObservableCollection<MyObject> collection = new ObservableCollection<MyObject>
{
new MyObject {Value1 = "One"},
new MyObject {Value1 = "Two"},
new MyObject {Value1 = "Tree"}
};
ObjectList = collection;
timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2)};
timer.Tick += timer_Tick;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
foreach (MyObject myObject in _objectList)
{
myObject.Value2 = "Something";
}
Application.Current.RootVisual.Dispatcher.BeginInvoke( () => RaisePropertyChanged(ObjectListPropertyName));
}
}
When the timer_tick is reached, I supposed the pivot control to refresh with the new values ... but I can't see any changes.
What do I miss ?
Thanks in advance for your help
I'm guessing that possibly updating the members of the list without updating the list itself is the problem. When you raise the property changed event - it is for the entire collection. The collection is still pointing to an equal reference of itself, despite the fact that the members have changed.
Try placing a breakpoint in the setter and see if the property changed event is fired.

Resources