In the first block below I intentionally miss named one of my binding statements so I could compare to my second block. The difference is in the property not found on 'ag2.item...' line.
item is my model.
In block 2 you can see that it is pointing to my view model (ag2.viewModel.itemViewModel).
What do I need to do in my XAML or my codebehind to get it to point to my class rather than the viewmodel?
Block 1:
BindingExpression path error: 'itemModel1' property not found on
'ag2.item, ag2, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null'. BindingExpression: Path='itemModel1'
DataItem='ag2.item, ag2, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null'; target element is
'Windows.UI.Xaml.Controls.TextBlock' (Name='null'); target property is
'Text' (type 'String')
Block 2:
BindingExpression path error:'itemModel' property not found on
'ag2.viewModel.itemViewModel, ag2, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null'. BindingExpression: Path='itemModel'
DataItem='ag2.viewModel.itemViewModel, ag2, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null'; target element is
'Windows.UI.Xaml.Controls.TextBlock' (Name='null'); target property is
'Source' (type 'String')
Code behind to Block 2:
itemViewModel VM = new itemViewModel((Int32)navigationParameter);
DataContext = VM;
I should also note that in block 1 I am doing my binding to a GridView where the ItemSource="{Binding item}" is set.
In block 2 I built my UI using grids and textblocks using this: Text="{Binding Path=itemModel}"
Update: In an effort to try to gain better understanding. I'm putting my code out there: Here is the XAML, below that will be the ViewModel and below that is my Model... I'm new at MVVM so I really don't know what I'm doing incorrectly. Any help is greatly appreciated.
XAML:
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="autoGarage2.VehicleItemDetailPage"
IsTabStop="false"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="using:autoGarage2.Common"
xmlns:local="using:autoGarage2"
xmlns:data="using:autoGarage2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<!-- Back button and page title -->
<Grid
Style="{StaticResource LayoutRootStyle}" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Style="{StaticResource PageHeaderTextStyle}" Grid.Column="1"/>
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="3*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Width="auto" Margin="50,0,0,0" VerticalAlignment="Top" >
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="White" BorderBrush="CornflowerBlue" BorderThickness="1">
<Image Source="{Binding Image}" Margin="50"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="CornflowerBlue">
<StackPanel Orientation="Horizontal" DataContext="{Binding vehicles}">
<TextBlock Text="{Binding VehicleMake}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource PageSubheaderTextStyle}" Margin="5"/>
<TextBlock Text="{Binding VehicleModel}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource PageSubheaderTextStyle}" Margin="5"/>
</StackPanel>
</StackPanel>
</Grid>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1">
<Grid Margin="20,0,0,20">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Vehicle Make:" Grid.Row="0" Grid.Column="0" FontSize="25" Foreground="Black" />
<TextBox Text="{Binding Path=VehicleMake}" Grid.Row="0" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1"/>
<TextBlock Text="Vehicle Model:" FontSize="25" Foreground="Black" Grid.Row="1" Grid.Column="0"/>
<TextBox Text="{Binding VehicleModel}" Grid.Row="1" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1"/>
<TextBlock Text="Vehicle Year:" FontSize="25" Foreground="Black" Grid.Row="2" Grid.Column="0"/>
<TextBox Text="{Binding VehicleYear}" Grid.Row="2" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1"/>
<TextBlock Text="License Plate:" FontSize="25" Foreground="Black" Grid.Row="3" Grid.Column="0"/>
<TextBox Text="" Grid.Row="3" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1"/>
<TextBlock Text="VIN #" FontSize="25" Foreground="Black" Grid.Row="4" Grid.Column="0"/>
<TextBox Text="" Grid.Row="4" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1" />
<TextBlock Text=" Current Mi/Km" FontSize="25" Foreground="Black" Grid.Row="5" Grid.Column="0"/>
<TextBox Text="" Grid.Row="5" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1"/>
<TextBlock Text="" FontSize="25" Foreground="Black" Grid.Row="6" Grid.ColumnSpan="2"/>
<TextBlock Text="Last Oil Change" FontSize="25" Foreground="Black" Grid.Row="7" Grid.Column="0"/>
<TextBox Text="" Grid.Row="7" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1"/>
<TextBlock Text="Last Oil Change Mi/Km" FontSize="25" Foreground="Black" Grid.Row="8" Grid.Column="0"/>
<TextBox Text="" Grid.Row="8" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1"/>
<TextBlock Text="" FontSize="25" Foreground="Black" Grid.Row="9" Grid.ColumnSpan="2"/>
<TextBlock Text="Reminder Mi/Km" FontSize="25" Foreground="Black" Grid.Row="10" Grid.Column="0"/>
<TextBox Text="" Grid.Row="10" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1"/>
<TextBlock Text="Reminder Month(s)" FontSize="25" Foreground="Black" Grid.Row="11" Grid.Column="0"/>
<TextBox Text="" Grid.Row="11" Grid.Column="1" FontSize="25" BorderBrush="CornflowerBlue" BorderThickness="1"/>
</Grid>
</StackPanel>
</Grid>
</Grid>
</common:LayoutAwarePage>
View Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using Windows.Foundation.Collections;
using System.IO;
namespace autoGarage2.viewModel
{
class vehicleViewModel
{
private IList<vehicle> m_vehicles;
private IList<vehicle> m_vehicleItem;
public IList<vehicle> vehicles
{
get { return m_vehicles; }
set { m_vehicles = value; }
}
public IList<vehicle> vehicleItem
{
get { return m_vehicleItem; }
set { m_vehicleItem = value; }
}
private IList<vehicle> getVehicleDetail(Int32 vId)
{
var vehicleItem =
from v in vehicles
where v.VehicleId == vId
select v;
if (vId > 0)
{
//vehicles.Clear();
m_vehicles = new List<vehicle>();
foreach (var item in vehicleItem)
{
m_vehicles = new List<vehicle>
{
new vehicle(item.VehicleId, item.VehicleMake.ToString(), item.VehicleModel.ToString(), item.VehicleYear, item.Image.ToString())
};
//vehicle myVehicle = new vehicle(item.VehicleId, item.VehicleMake.ToString(), item.VehicleModel.ToString(), item.VehicleYear, item.Image.ToString());
//m_vehicles.Add(myVehicle);
}
}
return m_vehicles;
}
public vehicleViewModel(Int32 vId)
{
m_vehicles = new List<vehicle>
{
new vehicle(1, "Mazda", "3", 2011, "Assets/car2.png"),
new vehicle(2, "Chevy", "Tahoe", 2004, "Assets/jeep1.png"),
new vehicle(3, "Honda", "Goldwing", 2007 ,"Assets/moto1.png")
};
if (vId > 0)
{
//m_vehicles = new List<vehicle>();
//m_vehicles =
//getVehicleDetail(vId);
m_vehicles = new List<vehicle>
{
new vehicle(2, "Chevy", "Tahoe", 2004, "Assets/jeep1.png"),
};
}
}
#region dbCode
//string dbName = "vehicle.db";
//var dbPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, dbName);
//using (var db = new SQLite.SQLiteConnection(dbPath))
// {
// var list = db.Table<vehicle>().ToList();
// m_vehicles = new List<vehicle>();
// for (Int32 i = 0; i < list.Count; i++)
// {
// //m_vehicles.Add(db.Table<vehicle>().ToList());
// }
// }
//foreach (vehicle item in m_vehicles)
//{
// AllItems.Add(item);
//}
#endregion
}
}
Model:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using SQLite;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
namespace autoGarage2
{
class vehicle : autoGarage2.Common.BindableBase
{
public vehicle()
{
}
public vehicle(string imagePath)
{
this._imagePath = imagePath;
}
public vehicle(Int32 vId, string vMake, string vModel, Int16 vYear, string imagePath)
{
this.m_vehicleID = vId;
this.m_vehicleMake = vMake;
this.m_vehicleModel = vModel;
this.m_vehicleYear = vYear;
this.m_vehicleName = vMake + " " + vModel;
this._imagePath = imagePath;
}
private Int32 m_vehicleID;
private String m_vehicleMake;
private String m_vehicleModel;
private Int16 m_vehicleYear;
private string m_vehicleName;
private ImageSource _image = null;
private String _imagePath = null;
private static Uri _baseUri = new Uri("ms-appx:///");
//[AutoIncrement, PrimaryKey]
public Int32 VehicleId
{
get
{
return m_vehicleID;
}
set
{
m_vehicleID = value;
OnPropertyChanged("VehicleId");
}
}
public String VehicleMake
{
get
{
return m_vehicleMake;
}
set
{
m_vehicleMake = value;
OnPropertyChanged("VehicleMake");
}
}
public String VehicleModel
{
get
{
return m_vehicleModel;
}
set
{
m_vehicleModel = value;
OnPropertyChanged("VehicleModel");
}
}
public Int16 VehicleYear
{
get
{
return m_vehicleYear;
}
set
{
m_vehicleYear = value;
OnPropertyChanged("VehicleYear");
}
}
public string VehicleName
{
get
{
return m_vehicleName;
}
set
{
m_vehicleName = value;
OnPropertyChanged("VehicleName");
}
}
public ImageSource Image
{
get
{
if (this._image == null && this._imagePath != null)
{
this._image = new BitmapImage(new Uri(vehicle._baseUri, this._imagePath));
}
return this._image;
}
set
{
this._imagePath = null;
this.SetProperty(ref this._image, value);
}
}
public void SetImage(String path)
{
this._image = null;
this._imagePath = path;
this.OnPropertyChanged("Image");
}
}
}
It sounds like you are trying to databind your TextBlock to a different object, not to the ViewModel (which is the DataContext of your window/control). If that is correct, you'll need to set the DataContext of the TextBlock or the parent Grid to the object you want to DataBind to.
The DataContext is used in determining the path to DataBind to for a control, and it inherits down the visual tree. So if your DataContext is set to MyViewModel, and you use Text="{Binding Path=itemModel}", your binding path will be MyViewModel.itemModel.
If you don't want to include MyViewModel in the binding path, you'll need to change the DataContext of the control in question, or of a containing control. For MVVM, this is often done by having the other object exposed as a property of the ViewModel. So if your MyViewModel had a property ItemModel:
public class ItemModel
{
public string Property1 { get; }
public string Property2 { get; }
}
public class MyViewModel
{
public ItemModel ItemModel { get; private set; }
}
Then your XAML could look like this (assuming MyViewModel is the DataContext of the parent window/control).
<Grid Grid.Row="1" DataContext="{Binding ItemModel}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding property1}"/>
<TextBlock Text="{Binding Property2}" Grid.Row="1"/>
</Grid>
And the two textboxes would be bound to Property1 and Property2 of the ItemModel object.
You seem to be trying to bind to a list but you are not using any ItemsControl in your XAML. You should probably use something like a ListView, bind its ItemsSource to your vehicles or vehicleItem lists, use an ItemTemplate/DataTemplate to define the look of each item in the collection, use ObservableCollection if your collection changes or raise INotifyPropertyChanged.PropertyChanged notifications if you swap out your collection, etc. Otherwise I would suggest reading something about binding ItemsControls or a general book about XAML, like Adam Nathan's WPF Unleashed. It seems like you are setting your m_vehicles only to replace it with a new one in the next statement. Also - you are setting the DataContext of the StackPanel to your list, which is allowed, but it does not work, since the DataContext of the elements of your StackPanel will still be the entire list and not its items, which is what you get by using an ItemsControl.
I was able to get my data to show up after a weekend of not looking at it. Basically I noticed that I was getting a binding error that stated that it couldn't find the property in my autoGarage2.vehicles list. So for grins I prefaced the binding like this:
{Binding vehicles[0].vehicleModel}
Next time I ran it, the data was there. After thinking about it some more, I decided to create a single object of vehicle and instead of populating the list object I'm populating just the single vehicle property. Now I'm doing something like this:
{Binding vehicleSingle.vehicleModel}
Thanks for every ones help. I guess this is just a nuance of how MVVM works in XAML...
Related
How can I get rid of that shadow behind my ContentDialog?
For the background, I've set the background to transparent, but it's still showing up. Also, according to the documentation, ContentDialog should have a "Shadow" property inherited from UIElement, but that doesn't appear to be a property that's available on my dialog, even though it's inherited from ContentDialog.
Here's my XAML:
<ContentDialog
x:Class="App.Views.HelperViews.CautionDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App.Views.HelperViews"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:control="using:App.Controls"
mc:Ignorable="d"
IsPrimaryButtonEnabled="False"
IsSecondaryButtonEnabled="False"
Padding="0"
BorderBrush="Transparent"
Background="Transparent"
Loaded="ContentDialog_Loaded">
<Grid Padding="0">
<Grid.RowDefinitions>
<RowDefinition Height="228*"/>
<RowDefinition Height="22*"/>
<RowDefinition Height="70*"/>
</Grid.RowDefinitions>
<Border BorderBrush="White" BorderThickness="4" CornerRadius="3">
<Grid Row="0" Background="{StaticResource YellowColor2}" CornerRadius="3">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Row="0" BorderBrush="{StaticResource White}" BorderThickness="0, 0, 0, 0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*" />
<ColumnDefinition Width="80*" />
</Grid.ColumnDefinitions>
<Border BorderBrush="White" BorderThickness="0 0 0 2" Grid.ColumnSpan="2" />
<TextBlock x:Name="Icon" Foreground="{StaticResource Black}" TextAlignment="Center" VerticalAlignment="Center" Text="{StaticResource Warning}" FontSize="50" Grid.Column="0" FontFamily="{StaticResource GlyphFontFamily}" />
<TextBlock x:Name="Issue" Padding="0 20 0 0" FontWeight="Bold" FontSize="{StaticResource FontSizeText3}" Grid.Column="1" Foreground="{StaticResource Black}" Text="Information only"/>
</Grid>
</Grid>
<Grid Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="80*" />
<RowDefinition Height="20*" />
</Grid.RowDefinitions>
<TextBlock x:Name="ResolveText" Grid.Row="0" Padding="20 20 20 0" FontSize="{StaticResource FontSizeText2}" TextWrapping="WrapWholeWords" Foreground="{StaticResource Black}" Text="Message text will go here. Message text will go here. Message text will go here. Message text will go here..."/>
<TextBlock x:Name="CodeRef" Grid.Row="1" Padding="20" FontSize="{StaticResource FontSizeText2}" Foreground="{StaticResource Black}" Text="Ref: foobar" />
</Grid>
</Grid>
</Border>
<control:WideHighlightedButton Grid.Row="2" x:Name="Zero" Margin="-4" Height="77" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" />
</Grid>
</ContentDialog>
And the code behind:
using Windows.UI.Xaml.Controls;
namespace App.Views.HelperViews
{
public partial class CautionDialog : ContentDialog
{
private string issue;
private string resolveText;
private string buttonText;
private string errorCode;
private string codeNumber;
public CautionDialog(string code)
{
//Get the error dialog box strings from the resource file...
var res = Windows.ApplicationModel.Resources.ResourceLoader.GetForViewIndependentUse("ErrorCodes");
errorCode = code;
issue = res.GetString(code + "_INFO");
resolveText = res.GetString(code + "_ACTION");
buttonText = res.GetString(code + "_BUTTON_1");
codeNumber = "4";
this.InitializeComponent();
}
private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
}
private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
}
private void ContentDialog_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if (issue == null || issue == string.Empty)
{
Issue.Text = "No message assigned for this code!!";
}
else
{
Issue.Text = issue;
}
if (resolveText == null || resolveText == string.Empty)
{
ResolveText.Text = "Code:" + errorCode;
}
else
{
ResolveText.Text = resolveText;
}
if (buttonText == null || buttonText == string.Empty)
{
this.CloseButtonText = "Need Button!";
}
else
{
this.CloseButtonText = buttonText;
}
string refText = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView().GetString("Ref/Text");
CodeRef.Text = refText + ": " + codeNumber;
}
}
}
If you want to disable it, the better way is set a new Translation , and make z value as low enough.
<ContentDialog
Transition="0,0,-100">
.
.
</ContentDialog>
I'm working in a Xamarin Form Project . The form entered values are not showing in the Binding context . Binding Context Always shows the Initial value not the Latest Value .I have added my forms xaml part and View related View model class.Is there any Addition configurations to enable 2 way binding
Xaml Page
<StackLayout Grid.Row="0" Grid.Column="0">
<Grid x:Name="grid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label x:Name="labelName" Grid.Row="0" Grid.Column="0" Margin="10" FontSize="6" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Start" Text="Name"/>
<Entry x:Name="textName" Grid.Row="0" Grid.Column="1" WidthRequest="100" FontSize="6" VerticalOptions="CenterAndExpand" HorizontalOptions="Start" HorizontalTextAlignment="Start" Text="{Binding Name,Mode=TwoWay}" />
<Label x:Name="labelAge" Grid.Row="1" Grid.Column="0" Margin="10" FontSize="6" Text="Age" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Start" />
<Entry x:Name="textAge" Grid.Row="1" Grid.Column="1" WidthRequest="100" FontSize="6" VerticalOptions="CenterAndExpand" HorizontalOptions="Start" HorizontalTextAlignment="Start" Text="{Binding Age,Mode=TwoWay}" />
<Label x:Name="labelAddress" Grid.Row="2" Grid.Column="0" Margin="10" FontSize="6" Text="Address" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Start" />
<Entry x:Name="textAddress" Grid.Row="2" Grid.Column="1" WidthRequest="100" FontSize="6" VerticalOptions="CenterAndExpand" HorizontalOptions="Start" HorizontalTextAlignment="Start" Text="{Binding Address,Mode=TwoWay}" />
<Label x:Name="labelNICNumber" Grid.Row="3" Grid.Column="0" Margin="10" FontSize="6" Text="NIC" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Start" />
<Entry x:Name="textNIC" Grid.Row="3" Grid.Column="1" WidthRequest="100" FontSize="6" VerticalOptions="CenterAndExpand" HorizontalOptions="Start" HorizontalTextAlignment="Start" Text="{Binding NIC,Mode=TwoWay}" />
<Button Grid.Row="4" Grid.Column="1" HeightRequest = "30" VerticalOptions="CenterAndExpand" HorizontalOptions="Start" FontSize="6" Text="Save" Clicked="UserSaveClick" />
</Grid>
</StackLayout>
ViewModel
public event PropertyChangedEventHandler PropertyChanged;
private string userName ;
private string name;
private int age ;
private bool isBusy;
private string address;
private int nic;
void OnPropertyChanged([CallerMemberName] string name = "")
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(name));
}
public int NIC
{
get { return nic; }
set
{
nic = value;
OnPropertyChanged();
}
}
public string Name
{
get { return name; }
set
{
name = value;
IsBusy = Name == "aa" ? true : false;
OnPropertyChanged();
OnPropertyChanged(nameof(DisplayMessage));
}
}
public int Age
{
get { return age; }
set
{
age = value;
OnPropertyChanged();
}
}
public string Address
{
get { return address; }
set
{
address = value;
OnPropertyChanged();
}
}
public string DisplayMessage
{
get
{
return "Hi " + name;
}
}
public bool IsBusy
{
get { return isBusy; }
set { isBusy = value; }
}
}
Also check that you properly setter method is not private. I lost some hours to find out this simple copy paste error.
I was getting this error in the debug output Binding: 'xxx' property not found on 'yyyy', target property: 'Xamarin.Forms.Entry.Text'.
by the way this error message is not super clear.
Can you check:
1.When entering text in the entry control,check it is hitting the break point in the view model for each property.
2.Check INotifyPropertyChanged is implemented.
3.Check by setting the hard code for the Text property of Entry control.
I want to insert a syncfusion linearlayout listview, but for some reason it's not displaying any items/data, and I'm not getting any errors at the same time, I tried changing binding syntax and a couple things, but I cannot seem to get it right.
This is my xaml:
<syncfusion:SfListView x:Name="listView"
ItemTemplate="{Binding Source={local2:BandInfoRepository}, Path=BandInfo, Mode=TwoWay}"
ItemSize="100"
AbsoluteLayout.LayoutBounds="1,1,1,1"
AbsoluteLayout.LayoutFlags="All" >
<syncfusion:SfListView.ItemTemplate>
<DataTemplate>
<Grid RowSpacing="0" Padding="0,12,8,0" ColumnSpacing="0" Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1" />
</Grid.RowDefinitions>
<Grid RowSpacing="0" Padding="8,0,8,10">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Source="{Binding Path=BandImage}"
Grid.Column="0"
Grid.Row="0"
HeightRequest="80"
WidthRequest="70"
HorizontalOptions="Start"
VerticalOptions="Start"
/>
<StackLayout Orientation="Vertical"
Padding="5,-5,0,0"
VerticalOptions="Start"
Grid.Row="0"
Grid.Column="1">
<Label Text="{Binding Path=BandName}"
FontAttributes="Bold"
FontSize="16"
BackgroundColor="Green"
TextColor="#000000" />
<Label Text="{Binding Path=BandDescription}"
Opacity="0.54"
BackgroundColor="Olive"
TextColor="#000000"
FontSize="13" />
</StackLayout>
</Grid>
<BoxView Grid.Row="1"
HeightRequest="1"
Opacity="0.75"
BackgroundColor="#CECECE" />
</Grid>
</DataTemplate>
</syncfusion:SfListView.ItemTemplate>
</syncfusion:SfListView>
And this is the class where I'm getting the data from:
public class BandInfo : INotifyPropertyChanged
{
private string bandName;
private string bandDesc;
private ImageSource _bandImage;
public string BandName
{
get { return bandName; }
set
{
bandName = value;
OnPropertyChanged("BandName");
}
}
public string BandDescription
{
get { return bandDesc; }
set
{
bandDesc = value;
OnPropertyChanged("BandDescription");
}
}
public ImageSource BandImage
{
get { return _bandImage; }
set
{
_bandImage = value;
OnPropertyChanged("BandImage");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
And just in case, this is how I'm filling the collection (BandInfoRepository.cs):
public class BandInfoRepository
{
private ObservableCollection<BandInfo> bandInfo;
public ObservableCollection<BandInfo> BandInfo
{
get { return bandInfo; }
set { this.bandInfo = value; }
}
public BandInfoRepository()
{
GenerateBookInfo();
}
internal void GenerateBookInfo()
{
string[] BandNames = new string[] {
"Nirvana",
"Metallica",
"Frank Sinatra"
};
string[] BandDescriptions = new string[] {
"Description",
"Description",
"Description"
};
bandInfo = new ObservableCollection<BandInfo>();
for (int i = 0; i < BandNames.Count(); i++)
{
var band = new BandInfo()
{
BandName = BandNames[i],
BandDescription = BandDescriptions[i],
BandImage = ImageSource.FromResource("Lim.Images.Image" + i + ".png")
};
bandInfo.Add(band);
}
}
}
I hope you guys can help me out as I've been stuck with this for a while now. Thanks in advance.
Looks like you unintentionally bind ItemTemplate twice and not bind any
ItemsSource even once.
We have looked into your code snippet and we have found that you have binded the underlying collection to ItemTemplate property instead of ItemsSource property. Further to bind the underlying collection you have to set your ViewModel(i.e. BandInfoRepository) as BindingContext for ContentPage. Please refer the below code snippets to know how to set BindingContext for your page and also to bind the underlying collection into the ItemsSource property.
Code Example:[XAML]
<ContentPage>
<ContentPage.BindingContext>
<local:BandInfoRepository/>
</ContentPage.BindingContext>
<ContentPage.Content>
<listView:SfListView x:Name="listView" ItemSize="70" ItemsSource="{Binding BandInfo}" >
<listView:SfListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid x:Name="grid" RowSpacing="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="1" />
</Grid.RowDefinitions>
<Grid RowSpacing="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding BandImage}"
VerticalOptions="Center"
HorizontalOptions="Center"
HeightRequest="50" Aspect="AspectFit"/>
<Grid Grid.Column="1"
RowSpacing="1"
Padding="10,0,0,0"
VerticalOptions="Center">
<Label Text="{Binding ContactName}"/>
</Grid>
</Grid>
<StackLayout Grid.Row="1" BackgroundColor="Gray" HeightRequest="1"/>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</listView:SfListView.ItemTemplate>
</listView:SfListView>
</ContentPage.Content>
</ContentPage>
For your assistance, we have attached the working sample link below.
Sample link: http://www.syncfusion.com/downloads/support/directtrac/186932/ze/ListViewSample905947849
I'm trying to create a custom Button with ListPickerFlyout using MVVM. The result that i wanna reach is something like that:
custom Button with ListPickerFlyout
My problem is how to bind the SelectedItem from ListPickerFlyout to the content TextBlock.
I'm using MVVM Light Windows Phone 8.1 (Store Appp).
My Xaml code:
<Button Background="White"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<!-- Content TextBlock -->
<TextBlock Text="{Binding MyVM.SelectedItem, Mode=TwoWay}"
Style="{StaticResource DefaultTextBlock}"
FontSize="22"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="10, 0, 0, 0"/>
<Image Height="20" Grid.Column="1"
VerticalAlignment="Center" HorizontalAlignment="Center"
Source="../Assets/icons/arrow_down.png"/>
</Grid>
<Button.Flyout>
<ListPickerFlyout PickerFlyoutBase.Title="$Items$"
ItemsSource="{Binding MyVM.listItems}"
SelectedItem="{Binding MyVM.SelectedItem, Mode=TwoWay}" >
<ListPickerFlyout.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding}"
Style="{StaticResource DefaultTextBlock}"
FontSize="22"/>
</StackPanel>
</DataTemplate>
</ListPickerFlyout.ItemTemplate>
</ListPickerFlyout>
</Button.Flyout>
And in MyVM i have
public string SelectedItem { get; set; }
Edit:
Solved the problem, i forgot to add RaisePropertyChanged("SelectedItem");.
So, in my MVVM class:
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != value)
{
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
}
Just need to add the RaisePropertyChanged("SelectedItem"); in MVVM class.
The complete code:
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != value)
{
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
}
I am using MVVM light on a Windows 8.1 Store app. I have a view model that has several properties on it that have no setters (their value is derived from a different property). Here is part of my ViewModel:
public float TotalAmount
{
get
{
if (!LineItems.Any())
return 0.0f;
return SubTotal + TotalFees - TotalDiscounts;
}
}
public float SubTotal
{
get
{
return !LineItems.Any() ? 0.0f : LineItems.Select(i => i.Price.Amount).Sum();
}
}
public float TotalFees
{
get
{
return !Fees.Any() ? 0.0f : Fees.Select(f => f.Amount).Sum();
}
}
public float TotalDiscounts
{
get
{
return !Discounts.Any() ? 0.0f : Discounts.Select(d => d.Amount).Sum();
}
}
public ObservableCollection<Discount> Discounts { get; set; }
public ObservableCollection<Fee> Fees { get; set; }
public Customer Customer { get; set; }
public ObservableCollection<OrderLineItem> LineItems { get; set; }
In the XAML, I bind to each of these properties, and want to update them when an Item is added to LineItems.
Here is the relevant part of the XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Text="SubTotal:" Style="{StaticResource OrderDetailsLabel}" />
<TextBlock Grid.Column="1" Style="{StaticResource OrderDetailsValue}"
Text="{Binding SubTotal, Converter={StaticResource MoneyConverter}, Mode=TwoWay}" />
<TextBlock Grid.Row="1" Text="Fees:" Style="{StaticResource OrderDetailsLabel}" />
<TextBlock Grid.Row="1" Style="{StaticResource OrderDetailsValue}" Grid.Column="1"
Text="{Binding TotalFees, Converter={StaticResource MoneyConverter}, Mode=TwoWay}" />
<TextBlock Grid.Row="2" Text="Discounts:" Style="{StaticResource OrderDetailsLabel}" />
<TextBlock Grid.Row="2" Style="{StaticResource OrderDetailsValue}" Grid.Column="1"
Text="{Binding TotalDiscounts, Converter={StaticResource MoneyConverter}, Mode=TwoWay}" />
<TextBlock Grid.Row="3" Text="Order Total:" Style="{StaticResource OrderDetailsLabel}" />
<TextBlock Grid.Row="3" Style="{StaticResource OrderDetailsValue}" Grid.Column="1"
Text="{Binding TotalAmount, Converter={StaticResource MoneyConverter}, Mode=TwoWay}" />
</Grid>
My Binding to the LineItems is working as expected, but the fields that are populated by doing math on the line items are not.
Line Item Binding functioning as expected:
<ListView ItemsSource="{Binding LineItems, Mode=TwoWay}"
SelectionMode="Single"
HorizontalAlignment="Stretch">
<ListView.ItemContainerStyle>
....
How can I get SubTotal, Total, etc. to update when LineItems changes?
Pretty simple:
Register the ObservableCollection<T>.CollectionChanged event for each of those collection. Since your desired properties are based on some calculation of the collection.
On event fire Raise the OnPropertyChanged on those properties.
Example how to raise the OnPropertyChanged/inotifypropertychanged
MSDN: inotifypropertychanged Example
Something like this in your constructor:
LineItems.CollectionChanged += (s, e) =>
{
RaisePropertyChanged("SubTotal");
RaisePropertyChanged("TotalFees");
RaisePropertyChanged("TotalDiscounts");
}
assuming your ViewModel implements INotifyPropertyChanged, and has a 'RaisePropertyChanged' method that raises the PropertyChanged event (e.g. You're using MVVM-Light's ViewModelBase as your baseclass).
I ended up solving this by raising the OnPropertyChanged event on in the handler for my AddLineItems message:
public NewOrderViewModel()
{
//Subscribe to messages
MessengerInstance.Register<OrderItemAdded>(this, o => AddOrderItem(o.LineItem));
MessengerInstance.Register<SelectedCustomer>(this, c => Customer = c.Customer);
Discounts = new ObservableCollection<Discount>();
Fees = new ObservableCollection<Fee>();
LineItems = new ObservableCollection<OrderLineItem>();
}
private void AddOrderItem(OrderLineItem lineItem)
{
//add Line Item to collection
LineItems.Add(lineItem);
//Raise events for properties derived from collection
RaisePropertyChanged("TotalAmount");
RaisePropertyChanged("SubTotal");
}