My checkbox is not binding with the member - xaml

Say we have a grid view which is binding with the data source MyInformation. One of column is a check box. I want to bind something with it.
ItemsSource="{Binding MyInformation}"
In the ViewModel.
public ObservableCollection<Container> MyInformation
{
get
{
if (this.myInformation == null)
{
this.myInformation = new ObservableCollection<Container>();
}
return this.myInformation;
}
set
{
if (this.myInformation != value)
{
this.myInformation = value;
this.OnPropertyChanged("MyInformation");
}
}
}
The class Container has a member "GoodValue".
public class Container
{
public bool GoodValue {get;set;}
//
}
I have the checkbox bind with the member.
<DataTemplate>
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding GoodValue, Converter={StaticResource ShortToBooleanConverter}}" Click="CheckBox_Checked"></CheckBox>
</DataTemplate>
I don't have the property GoodValue created in ViewModel as I think GoodValue is a member of Container. The ObservableCollection includes it automatically.
The problem is each time I read the data from the database. The checkbox is unchecked. So I doubt my code. Thanks for hint.

You can do two things:
Check if there are some binding errors
Implement INotifyPropertyChanged interface into your class Container.
public class Container:INotifyPropertyChanged
{
private bool _goodValue;
public string GoodValue
{
get
{
return _goodValue;
}
set
{
_goodValue = value;
OnPropertyChanged("GoodValue");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
public event PropertyChangedEventHandler PropertyChanged;
}
The ObservableCollection is usefull if you want to notify to your view when a new item is inserted or deleted from the collection, but if the object contained inside it doesn't implement InotifyPropertyChanged, the changes to properties of that object won't affect any change to your view.

Related

Image doesn't show in Xamarin.forms (PCL)

I have an image withn name fb.png and it's in root project(prtable) and I add this image to Resource>drawble in Droid project.
Thees is my MainPage.xaml code:
<Image x:Name="img1"></Image>
And Thees is my MainPage.xaml.cs code:
public MainPage()
{
InitializeComponent();
ImageSource img = ImageSource.FromResource("App2.fb.png");
img1.Source = img;
img1.Aspect = Aspect.AspectFit;
img1.BackgroundColor = Color.Navy;
}
What changed is need that image will be appeared?
If the file is saved in the Resources/Drawable directory, then you use FromFile, not FromResource. FromResource is used for images packaged as embedded resources in your built library.
You also need to specify the exact name of the file as it appears in Resources/Drawable, so this should do it:
public MainPage()
{
InitializeComponent();
ImageSource img = ImageSource.FromFile("fb.png");
img1.Source = img;
img1.Aspect = Aspect.AspectFit;
img1.BackgroundColor = Color.Navy;
}
Here is a full implementation of MVVM bound image resource to Image control. You need to set your viewmodel as the context of your page where the XAML is. Also accessing as "App2.fb.png" seems odd, it should just be fb.png. That might be a simpler fix.. just rename the image source to the exact name of the image as listed in Droid > resources
XAML
<Image
Aspect="AspectFit"
Source="{Binding PropertyImageStatusSource}">
Base ViewModel
Have your viewmodels inherit from a viewmodel base class so INotifyPropertyChanged is implemented on your accessors universally.
public class _ViewModel_Base : INotifyPropertyChanged
{
//figure out what is getting set
public virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
public event PropertyChangedEventHandler PropertyChanged;
//attach handler with property name args to changing property, overridable in inheriting classes if something else needs to happen on property changed
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
ViewModel
Public MyViewModel : _ViewModel_Base
{
private string ImageStatusSource = "fb.png";
public string PropertyImageStatusSource
{
set { SetProperty(ref ImageStatusSource, value); }
get { return ImageStatusSource; }
}
}

Have complex object update in view when property changed - property changed event not fired - WinRT/XAML

I have a WinRT app with a number of Users, Projects, Meetings, etc.
I have a main screen, with a main screen view model, which should display CurrentUser and has a ListView bound to CurrentUser.ProjectList.
I initialise CurrentUser in the ViewModel using a UserProvider class that gets all the required information from the database.
My problem then becomes very similar to this: Subscribe to INotifyPropertyChanged for nested (child) objects
I have a user and project model:
public class User
{
public int id { get; set; }
public string ForeName { get; set; }
public string Surname { get; set; }
... etc ...
public ObservableCollection<Project> ProjectList { get; set; }
public ObservableCollection<User> FriendList { get; set; }
... constructor
}
public class Project
{
public String Name { get; set; }
public int Id { get; set; }
public List<User> Users { get; set; }
public List<Meeting> Meetings { get; set; }
.. constructor ...
}
A view model with the following:
class HomeScreenViewModel : INotifyPropertyChanged {
private User _currentUser;
public User CurrentUser
{
get { return this._currentUser; }
set
{
if (Equals(_currentUser, value)) return;
this._currentUser = value;
RaisePropertyChanged("CurrentUser");
}
}
//[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
... I have a method in this view model that gets the current user
public async Task<bool> GetLoggedInUserAsync()
{
int testId = 0;
CurrentUser = await userProvider.GetCurrentUser(testId);
UserProjects = await userProvider.GetUsersProject(CurrentUser);
CurrentUser.ProjectList = UserProjects;
return true;
}
That is called in the view's loadState
public MainPage()
{
this.InitializeComponent();
addMeeting = new AddMeetingFlyout();
_vm = new HomeScreenViewModel();
this.DataContext = _vm;
}
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
await _vm.GetLoggedInUserAsync()
}
And my bindings in the XAML, for ProjectList and ForeName, for example, are as follows:
<CollectionViewSource
x:Name="projectsViewSource"
Source="{Binding CurrentUser.ProjectList}"/>
...
<ListView
x:Name="projectList"
ItemsSource="{Binding Source={StaticResource projectsViewSource}}"
Grid.Row="1"
SelectionMode="None"
Style="{StaticResource DraggableListView}"
ScrollViewer.VerticalScrollBarVisibility="Visible"
IsItemClickEnabled="True"
>
<ListView.ItemTemplate>
<DataTemplate>
<Button Style="{StaticResource ProjectTileButton}" Content="{Binding Name}" Click="ProjectItem_Click" />
</DataTemplate>
</ListView.ItemTemplate>
<AddDeleteThemeTransition/>
</ListView>
...
<Button ...>
<TextBlock ...">
<Run Text="{Binding CurrentUser.ForeName}" />
</TextBlock>
</Button>
The button content, CurrentUser.ForeName fires an INotifyPropertyChanged event when CurrentUser is first initialised in the viewmodel. This is reflected in the view - but any further changes to CurrentUser.ForeName do not fire any subsequent INotifyPropertyChanged events. The ProjectList is also not displayed in the view and does not fire an INotifyPropertyChanged event even though I know it is there.
I have spent many days looking at implementing INotifyPropertyChanged so that changes to nested child complex objects (such as CurrentUser.ProjectList) will propagate up to the view. At the minute, the only way this happens is if I force a call to
this._currentUser = value;
RaisePropertyChanged("CurrentUser");
which I am testing with a button that calls a method called MakeChange() in the viewmodel
public void MakeChange()
{
User updatedCurrentUser = CurrentUser;
CurrentUser = updatedCurrentUser;
}
This works, so I know for a fact all the data is coming correctly from the database and all is as it should be - one less thing to worry about!
However, I simply cannot get the view to display user projects on page load, or when new projects are added.
I tried implementing this solution: https://gist.github.com/thojaw/705450, however, the WinRT reflection capabilites have changed and I am not sure how to get the following liens to work within the context of my project, as this is beyond me:
//from property
//in _type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
//where _inotifyType.IsAssignableFrom(property.PropertyType)
//select property;
Any help would be greatly appreciated - I honestly thought all I had to do was bind CurrentUser.ProjectList to a ListView.
As you are replacing the entire ObservableCollection itself, then you will also need to introduce another property changed event and backing field for the collection property.
There is a good example of this here

How to bind a string from singleton in xaml (WinRT / C#)

i've created a Singleton which contains a string.
Now i want to bind this string to a TextBlock an Xaml.
<TextBlock Visibility="Visible" Text="{Binding singleton.Instance.newsString, Mode=TwoWay}"/>
When i run the WinRT App, the TextBlock-Text-String is empty.
EDIT 1:
Now it runs. But when i change the string in the singleton the TextBlock does not update.
Here is the c# code from my singleton
namespace MyApp
{
public sealed class singleton : INotifyPropertyChanged
{
private static readonly singleton instance = new singleton();
public static singleton Instance
{
get
{
return instance;
}
}
private singleton() { }
private string _newsString;
public string newsString
{
get
{
if (_newsString == null)
_newsString = "";
return _newsString;
}
set
{
if (_newsString != value)
{
_newsString = value;
this.RaiseNotifyPropertyChanged("newsString");
}
}
}
private void RaiseNotifyPropertyChanged(string property)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(property));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
In my code behind the xaml i do this
singleton.Instance.newsString = "Breaking news before init";
this.Resources.Add("newsStringResource", singleton.Instance.newsString);
this.InitializeComponent();
singleton.Instance.newsString = "Breaking news AFTER init";
and in the xaml i bind the Resource with
<TextBlock Visibility="Visible" Text="{StaticResource newsStringResource}" />
With this code the TextBlock shows "Breaking news before init".
Whats wrong now?
Add your singleton to app resources using code behind before the TextBlock is constructed and reference the singleton by key.

Why does FlipView ignore SelectedItem

I'd like to use a FlipView to display some items and start showing a specific item.
For this, I have defined a view model class:
class MyDataContext
{
public MyDataContext()
{
Items = new List<MyClass>();
Items.Add(new MyClass("1"));
Items.Add(new MyClass("2"));
Items.Add(new MyClass("3"));
SelectedItem = Items[1];
}
public List<MyClass> Items { get; set; }
public MyClass SelectedItem { get; set; }
}
As you can see, the selected item is not the first item.
Now for the XAML:
<FlipView ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}"></FlipView>
However, when I run the app, the flip view shows the first item, not the second item.
Is this intentional?, or is it a bug?
Try this
<FlipView
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
your SelectedItem needs to be a TwoWay binding for it to work, since the value is set by both the control and the view model.
Was having the same issue with the FlipView and unable to get the BindableBase or the TwoWay option to work. Because the order of the list was not really a topic for me, I've created a method to reorder the ItemsSource, to start with the SelectedItem as being the first item in the Collection.
In the underlying code, the result is the new ItemsSource for the FlipView, instead of the previous List elements.
public static List<T> ReorderList(List<T> elements, T selectedElement)
{
var elementIndex = elements.FindIndex(x => x.Id == selectedElement.Id);
var result = new List<T>();
foreach (var item in elements)
{
if (elementIndex .Equals(elements.Count))
{
elementIndex = 0;
}
result.Add(elements[elementIndex]);
elementIndex++;
}
return result;
}
On top of what Filip stated, you're class (MyDataContext) needs to notify the UI that the property has changed. Your ViewModel must implement INotifyPropertyChanged and the property needs to fire the PropertyChanged event
public class ViewModel : INotifyPropertyChanged
{
private object _selectedItem;
public object SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
}
You can also use the BindableBase class that comes with the sample apps
public class ViewModel : BindableBase
{
private object _selectedItem;
public object SelectedItem
{
get { return this._selectedItem; }
set { this.SetProperty(ref this._selectedItem, value); }
}
}
It's look like a bug.
If you debug your code you will notice that at first your SelectedItem in VM set to the right element, then it sets to null and after that it sets to the first element of FlipView's ItemsSource collection.
As a workaround I see setting SelectedItem of VM after Loaded event of FlipView is raised.

Silverlight MVVM, stop SelectionChanged triggering in response to ItemsSource reset

I have two ComboBoxes, A & B, each bound to an Observable Collection. Each has a SelectionChanged trigger is attached which is intended to catch when the user changes a selection. The trigger passes the selection to a Command.
The collections implement INotifyPropertyChanged in that, in the Setter of each, an NotifyPropertyChanged event is fired. This is needed (in the MVVM approach) to notify the UI (the View) that the ComboBox's contents have changed.
The two ComboBoxes are interdependent - changing the selection in A causes B to be repopulated with new items.
Now, the problem is that B's SelectionChanged trigger fires in response to its collection being repopulated (as well as the user changing a selection). Due to the complexity of the code in the Command this is a huge waste of resources.
I could in theory stop this by not raising the NotifyPropertyChanged event when B's collection is set (because, looking at the Call Stack, this is what seems to cause the SelectionChanged trigger to fire), however the MVVM approach depends on this to keep the UI refreshed.
Any suggestions?
Why does ComboB need a SelectionChanged event? You can just bind the selected item directly into a property on the VM.
The way i have tackled this previously was to bind ComboA's selected item into the VM. In the setter for that property, i recalculate the available items for ComboB and assign them to another property on the VM, and ComboB's ItemsSource is bound to this property. Of course that property will notify (using INotifyPropertyChanged), but nothing else needed to be done, my ComboB did not have a SelectionChanged event. By using this method i didn't need a SelectionChanged on ComboA either, which keeps the view's code behind nice and sparse - everything is handled in the VM and regular databinding takes care of the rest.
Edit:
Here is an example of adjusting the required lists from within the property setters:
public class MyViewModel : INotifyPropertyChanged
{
//ItemsSource of ComboA is bound to this list
public List<SomeObject> ComboAList
{
get { return _comboAList; }
set { _comboAList = value; }
}
//ItemsSource of ComboB is bound to this list
public List<SomeObject> ComboBList
{
get { return _comboBList; }
set
{
_comboBList = value;
OnPropertyChanged("ComboBList");
}
}
//ItemsSource of the dataGrid is bound to this list
public List<SomeObject> DataGridList
{
get { return _datagridList; }
set
{
_datagridList = value;
OnPropertyChanged("DataGridList");
}
}
//SelectedItem of ComboA is bound to this property
public SomeObject FirstSelectedItem
{
get { return _firstSelectedItem; }
set
{
_firstSelectedItem = value;
RefreshListForComboB();
}
}
//SelectedItem of ComboB is bound to this property
public SomeObject SecondSelectedItem
{
get { return _secondSelectedItem; }
set
{
_secondSelectedItem = value;
RefreshListForDataGrid();
}
}
private void RefreshListForComboB()
{
//do whatever is necessary to filter or create a list for comboB
ComboBList = doSomethingThatReturnsAListForComboB();
}
private void RefreshListForDataGrid()
{
//do whatever is necessary to filter or create the list for the DataGrid
DataGridList = doSomethingThatReturnsAListForDataGrid();
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private List<SomeObject> _comboAList, _comboBList, _datagridList;
private SomeObject _firstSelectedItem, _secondSelectedItem;
}
And here is a slightly different way to do it, using a PropertyChange event handler on the VM, this simply changes where the list updating happens. This is arguably a better way of doing it than the first sample as it means the property setters don't have side effects:
public class MyViewModel : INotifyPropertyChanged
{
public MyViewModel()
{
this.PropertyChanged += new PropertyChangedEventHandler(MyViewModel_PropertyChanged);
}
private void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "FirstSelectedItem":
RefreshListForComboB();
break;
case "SecondSelectedItem":
RefreshListForDataGrid();
break;
}
}
//ItemsSource of ComboA is bound to this list
public List<SomeObject> ComboAList
{
get { return _comboAList; }
set { _comboAList = value; }
}
//ItemsSource of ComboB is bound to this list
public List<SomeObject> ComboBList
{
get { return _comboBList; }
set
{
_comboBList = value;
OnPropertyChanged("ComboBList");
}
}
//ItemsSource of the dataGrid is bound to this list
public List<SomeObject> DataGridList
{
get { return _datagridList; }
set
{
_datagridList = value;
OnPropertyChanged("DataGridList");
}
}
//SelectedItem of ComboA is bound to this property
public SomeObject FirstSelectedItem
{
get { return _firstSelectedItem; }
set
{
_firstSelectedItem = value;
OnPropertyChanged("FirstSelectedItem");
}
}
//SelectedItem of ComboB is bound to this property
public SomeObject SecondSelectedItem
{
get { return _secondSelectedItem; }
set
{
_secondSelectedItem = value;
OnPropertyChanged("SecondSelectedItem");
}
}
private void RefreshListForComboB()
{
//do whatever is necessary to filter or create a list for comboB
ComboBList = doSomethingThatReturnsAListForComboB();
}
private void RefreshListForDataGrid()
{
//do whatever is necessary to filter or create the list for the DataGrid
DataGridList = doSomethingThatReturnsAListForDataGrid();
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private List<SomeObject> _comboAList, _comboBList, _datagridList;
private SomeObject _firstSelectedItem, _secondSelectedItem;
}