how rebind silverlight datagrid - asp.net

I am just doing simple example in Silverlight, which retrieves data from database, can also insert, update and delete
I use child window for insert command, when I click "OK" Button at this ChildWindow it insert's in database but not renders on page(Silverlight content), there is same records therefore in database really inserts information. only after again re-lunch this page, it shows correctly(retrieves all data from server)
I'll post my source
this is Customers.xaml file
<UserControl x:Class="Store.Customers"
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:mv="clr-namespace:Store.ViewModel"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="1000">
<UserControl.Resources>
<mv:ViewModel x:Key="ViewModel"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="127*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="130*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="91*" />
<RowDefinition Height="99*" />
<RowDefinition Height="110*" />
</Grid.RowDefinitions>
<Button Name="btnEdit" Content="Edit" HorizontalAlignment="Right" Grid.Column="1" Width="55" Height="30" Margin="0,225,0,0" Click="btnEdit_Click" />
<data:DataGrid Name="dgCustomer"
AutoGenerateColumns="False" VerticalScrollBarVisibility="Visible"
ItemsSource="{Binding PagedView, Mode=TwoWay, Source={StaticResource ViewModel}}"
Grid.Row="1" Grid.Column="1">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="ID" Binding="{Binding CustomerID}"/>
<data:DataGridTextColumn Header="CompanyName" Binding="{Binding CompanyName}"/>
<data:DataGridTextColumn Header="ContactName" Binding="{Binding ContactName}"/>
<data:DataGridTextColumn Header="ContactTitle" Binding="{Binding ContactTitle}"/>
<data:DataGridTextColumn Header="Address" Binding="{Binding Address}"/>
<data:DataGridTextColumn Header="City" Binding="{Binding City}"/>
<data:DataGridTextColumn Header="Region" Binding="{Binding Region}"/>
<data:DataGridTextColumn Header="PostalCode" Binding="{Binding PostalCode}"/>
<data:DataGridTextColumn Header="Country" Binding="{Binding Country}"/>
<data:DataGridTextColumn Header="Phone" Binding="{Binding Phone}"/>
<data:DataGridTextColumn Header="Fax" Binding="{Binding Fax}"/>
<data:DataGridCheckBoxColumn Header="IsCitizen" Binding="{Binding IsCitizen}"/>
</data:DataGrid.Columns>
</data:DataGrid>
<data:DataPager HorizontalContentAlignment="Center" x:Name="myPager"
Source="{Binding ItemsSource, ElementName=dgCustomer}"
AutoEllipsis="True"
PageSize="10" Grid.Row="2" Grid.Column="1" VerticalAlignment="Top"/>
</Grid>
and this codebehinde
public partial class Customers : UserControl
{
public Customers()
{
InitializeComponent();
}
private void btnEdit_Click(object sender, RoutedEventArgs e)
{
new AddNewCustomer().Show();
}
}
this is childwindow
<controls:ChildWindow x:Class="Store.AddNewCustomer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:mv="clr-namespace:Store.ViewModel"
Width="450" Height="350"
Title="AddNewCustomer" >
<controls:ChildWindow.Resources>
<mv:ViewModel x:Key="ViewModel"/>
</controls:ChildWindow.Resources>
<Grid x:Name="LayoutRoot" Margin="2">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.RowDefinitions >
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="30*"></ColumnDefinition>
<ColumnDefinition Width="70*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Customer ID :" VerticalAlignment="Center" Margin="2,0,0,0" />
<TextBox Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Margin="2,0" x:Name="txtCustomerID"
Text="{Binding CustomerID, Mode=TwoWay, Source={StaticResource ViewModel}}" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Company Name :" VerticalAlignment="Center" Margin="2,0,0,0" />
<TextBox Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" Margin="2,0" x:Name="txtCompanyName"
Text="{Binding CompanyName, Mode=TwoWay, Source={StaticResource ViewModel}}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Contact Name :" VerticalAlignment="Center" Margin="2,0,0,0" />
<TextBox Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" Margin="2,0" x:Name="txtContactName" />
<TextBlock Grid.Row="4" Grid.Column="0" Text="Contact Title :" VerticalAlignment="Center" Margin="2,0,0,0" />
<TextBox Grid.Row="4" Grid.Column="1" VerticalAlignment="Center" Margin="2,0" x:Name="txtContactTitle" />
<TextBlock Grid.Row="5" Grid.Column="0" Text="Address :" VerticalAlignment="Center" Margin="2,0,0,0" />
<TextBox Grid.Row="5" Grid.Column="1" VerticalAlignment="Center" Margin="2,0" x:Name="txtAddressTitle" />
<TextBlock Grid.Row="6" Grid.Column="0" Text="City :" VerticalAlignment="Center" Margin="2,0,0,0" />
<TextBox Grid.Row="6" Grid.Column="1" VerticalAlignment="Center" Margin="2,0" x:Name="txtCity" />
<TextBlock Grid.Row="7" Grid.Column="0" Text="Country :" VerticalAlignment="Center" Margin="2,0,0,0" />
<TextBox Grid.Row="7" Grid.Column="1" VerticalAlignment="Center" Margin="2,0" x:Name="txtCountry" />
</Grid>
<Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
<Button x:Name="OKButton" Content="OK" Width="75" Height="23" HorizontalAlignment="Right" Click="OKButton_Click"
Margin="0,12,79,0" Grid.Row="1" Command="{ Binding AddNewCustomer, Mode=TwoWay, Source={StaticResource ViewModel} }"/>
</Grid>
this is My ViewModel
public class ViewModel : BaseViewModel
{
#region Fields
public ObservableCollection<Customer> _items;
public PagedCollectionView _view;
public string _customerID;
public string _companyName;
#endregion
#region Constructors
public ViewModel()
{
if (!this.IsDesignTime)
this.LoadCustomer();
}
#endregion
#region Properties
public ICommand AddNewCustomer { get { return new AddNewCustomerInfo(this); } }
public ObservableCollection<Customer> Items
{
get { return this._items; }
set
{
this._items = value;
this.OnPropertyChanged("Items");
}
}
public PagedCollectionView PagedView
{
get { return this._view; }
set
{
this._view = value;
this.OnPropertyChanged("PagedView");
}
}
public string CustomerID
{
get { return this._customerID;}
set
{
this._customerID = value;
this.OnPropertyChanged("CustomerID");
}
}
public string CompanyName
{
get { return this._companyName; }
set
{
this._companyName = value;
this.OnPropertyChanged("CompanyName");
}
}
#endregion
#region Methods
public void LoadCustomer()
{
DataServiceClient webService = new DataServiceClient();
webService.GetCustomersCompleted += new EventHandler<GetCustomersCompletedEventArgs>(webService_GetCustomersCompleted);
webService.GetCustomersAsync();
}
public void webService_GetCustomersCompleted(object sender, GetCustomersCompletedEventArgs e)
{
Items = e.Result;
PagedCollectionView pageView = new PagedCollectionView(Items);
pageView.PageSize = 10;
PagedView = pageView;
}
public void CreateCustomer()
{
DataServiceClient webservice = new DataServiceClient();
Customer cust = new Customer();
cust.CustomerID = this.CustomerID;
cust.CompanyName = this.CompanyName;
webservice.InsertCustomerCompleted += new EventHandler<InsertCustomerCompletedEventArgs>(webservice_InsertCustomerCompleted);
webservice.InsertCustomerAsync(cust);
LoadCustomer();
}
void webservice_InsertCustomerCompleted(object sender, InsertCustomerCompletedEventArgs e)
{
this.CreateResult = e.Result;
}
#endregion
}
public class AddNewCustomerInfo : ICommand
{
#region Fields
public ViewModel ViewModel { get; set; }
#endregion
#region Constructors
public AddNewCustomerInfo(ViewModel viewModel)
{
this.ViewModel = viewModel;
}
#endregion
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
this.ViewModel.CreateCustomer();
}
}
Grid and childwindow looks like this

As a simple basic solution, i would do this:
change your InsertCustomer web service call to return the updated Customer object that it just saved. This is so you will get an updated copy of the data object, complete with any keys/IDs. Doing this is a reasonably efficient way to do it, as you are making a call and accessing the database anyway, there is no point making two calls when it can be done in one.
once you've changed your webservice contract and regenerated your client proxy, the InsertCustomerCompletedEventArgs Result property should contain the updated Customer object. If you now add this data object to your PagedCollectionView it will automatically show up in your grid (as the PagedCollectionView implements INotifyCollectionChanged so the DataGrid binding will pick it up straight away, although be aware that paging may mean it isn't visible in the list you are currently looking at).

Related

Load ContentView inside CarouselView in Xamarn forms

I am trying to create a scrollable tabs in Xamarin.Forms with CollectionView and CarouselView as specified in this link. I need to load different ContentView in CarouselView based on the Tab selected in the header.
I tried like below but the ContentView is not displaying..
Below is xaml Code:
<Grid x:DataType="{x:Null}" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="45" />
<RowDefinition Height="45" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<CollectionView
x:Name="CustomTabsView"
Grid.Row="1"
HorizontalScrollBarVisibility="Never"
ItemSizingStrategy="MeasureAllItems"
ItemsSource="{Binding TabVms}"
ItemsUpdatingScrollMode="KeepItemsInView"
SelectedItem="{Binding CurrentTabVm, Mode=TwoWay}"
SelectionMode="Single"
VerticalScrollBarVisibility="Never">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="local:TabViewModel">
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="3" />
</Grid.RowDefinitions>
<Label
x:Name="TitleLabel"
Grid.Row="0"
Padding="15,0"
FontAttributes="Bold"
FontSize="Small"
HeightRequest="50"
HorizontalTextAlignment="Center"
Text="{Binding Title}"
TextColor="White"
VerticalTextAlignment="Center" />
<BoxView
x:Name="ActiveIndicator"
Grid.Row="1"
BackgroundColor="Red"
IsVisible="{Binding IsSelected, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<CarouselView
Grid.Row="2"
CurrentItem="{Binding CurrentTabVm, Mode=TwoWay}"
CurrentItemChanged="CarouselView_CurrentItemChanged"
HorizontalScrollBarVisibility="Never"
IsScrollAnimated="True"
IsSwipeEnabled="True"
ItemsSource="{Binding TabVms}"
VerticalScrollBarVisibility="Never">
<CarouselView.ItemTemplate>
<DataTemplate x:DataType="local:TabViewModel">
<ContentView
x:Name="dynamiccontent"
BackgroundColor="White"
Content="{Binding DynamicContentView, Mode=TwoWay}" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</Grid>
.cs file Code
private void CarouselView_CurrentItemChanged(object sender, CurrentItemChangedEventArgs e)
{
var x = e.CurrentItem as TabItem;
var viewModel = BindingContext as xxxViewModel;
if(x.Header == Tab1)
{
viewModel.TabVms[0].DynamicContentView = new Page1();
}
if(x.Header == Tab2)
{
viewModel.TabVms[1].DynamicContentView = new Page2();
}
}
Any help is appreciated!
You could use DataTemplateSelector.
Creating a DataTemplateSelector:
class DymaicDataTemplateSelector : DataTemplateSelector
{
public DataTemplate Tab1Template { get; set; }
public DataTemplate Tab2Template { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return ((TabViewModel)item).Header == "Tab1" ? Tab1Template : Tab2Template;
}
}
Consuming a DataTemplateSelector in XAML:
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="tab1Template" x:DataType="local:TabViewModel">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label
Grid.Row="0"
Margin="10"
LineBreakMode="WordWrap"
Text="{Binding Content}"
TextColor="Red"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="tab2Template" x:DataType="local:TabViewModel">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label
Grid.Row="0"
Margin="10"
LineBreakMode="WordWrap"
Text="{Binding Content}"
TextColor="Green"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
<local:DymaicDataTemplateSelector
x:Key="dymaicDataTemplateSelector"
Tab1Template="{StaticResource tab1Template}"
Tab2Template="{StaticResource tab2Template}" />
</ResourceDictionary>
</ContentPage.Resources>
Assign it to the ItemTemplate property:
<CarouselView
Grid.Row="2"
CurrentItem="{Binding CurrentTabVm, Mode=TwoWay}"
CurrentItemChanged="CarouselView_CurrentItemChanged"
HorizontalScrollBarVisibility="Never"
IsScrollAnimated="True"
IsSwipeEnabled="True"
ItemTemplate="{StaticResource dymaicDataTemplateSelector}"
ItemsSource="{Binding TabVms}"
VerticalScrollBarVisibility="Never" />

Binding IsVisible to a bool property in Xamarin Forms

I've got a label that I want to bind to a boolean property (HasNotifications). However, when the property is false, the label stays visible. If I set the IsVisible property to false in the XAML, the label isn't visible so the issue appears to be with the binding.
XAML:
<AbsoluteLayout
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Grid
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label
Text="Title"
HorizontalOptions="Center"
VerticalOptions="Center"
TextColor="White"
FontSize="Large"
FontAttributes="Bold"
Margin="5"
BindingContext="{x:Reference DashboardPageView}"
Grid.Row="0" />
<Label
Text="Notifications"
HorizontalOptions="Start"
VerticalOptions="Center"
TextColor="White"
FontSize="Medium"
FontAttributes="Bold"
Margin="3"
BindingContext="{x:Reference DashboardPageView}"
IsVisible="{Binding HasNotifications}"
Grid.Row="1" />
</Grid>
</AbsoluteLayout>
My viewmodel:
public bool HasNotifications
{
get => this.hasNotifications;
set => this.SetProperty(ref this.hasNotifications, value);
}
I don't think you have set the correct BindingContext. The HasNotifications is a property of your ViewModel while the BindingContext you set to your label is DashboardPageView.
I wrote a simple demo and hope you can get some idea from it:
In xaml:
<Grid
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label
Text="Title"
HorizontalOptions="Center"
VerticalOptions="Center"
TextColor="Black"
FontSize="Large"
FontAttributes="Bold"
Margin="5"
Grid.Row="0" />
<Label
Text="Notifications"
HorizontalOptions="Start"
VerticalOptions="Center"
TextColor="Black"
FontSize="Medium"
FontAttributes="Bold"
Margin="3"
IsVisible="{Binding HasNotifications}"
Grid.Row="1" />
<Button Text="change HasNotifications" Clicked="Button_Clicked" Grid.Row="2"/>
</Grid>
In cs:
public partial class MainPage : ContentPage
{
ViewModel myViewModel;
public MainPage()
{
InitializeComponent();
myViewModel = new ViewModel();
BindingContext = myViewModel;
}
private void Button_Clicked(object sender, EventArgs e)
{
myViewModel.HasNotifications = !myViewModel.HasNotifications;
}
}
public class ViewModel : INotifyPropertyChanged
{
bool _HasNotifications;
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel()
{
}
public bool HasNotifications
{
set
{
if (_HasNotifications != value)
{
_HasNotifications = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("HasNotifications"));
}
}
}
get
{
return _HasNotifications;
}
}
}
Feel free to ask me any question if you have.

How to get the itemlistview details when a button is clicked

When a Add to cart button is clicked i want clicked row to add to local database.
i tried to implement clicked option, but is shows System.InvalidCastException: Specified cast is not valid.
My Xaml is :
<controls:FlowListView x:Name="gallery"
FlowColumnCount="2"
SeparatorVisibility="Default"
HasUnevenRows="True"
FlowItemsSource="{Binding ItemsGallery}"
FlowUseAbsoluteLayoutInternally="True"
FlowItemTapped="OnFlowItemTapped"
FlowColumnExpand="Proportional"
BackgroundColor="White">
<controls:FlowListView.FlowColumnTemplate>
<DataTemplate>
<StackLayout>
<Frame BorderColor="#DCDCDC" HasShadow="True" Margin="2,2,2,2" CornerRadius="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="35"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="35"/>
</Grid.RowDefinitions>
<ffimageloading:CachedImage Source="{Binding image}" Grid.Row="0" LoadingPlaceholder="ItemsGallery" HeightRequest="120" WidthRequest="120" />
<Label Grid.Row="1"
VerticalOptions="End"
FontAttributes="Bold"
FontSize="Medium"
HorizontalTextAlignment="Start"
TextColor="Black"
Text="{Binding name}" />
<Label Grid.Row="2" HorizontalOptions="Start"
VerticalOptions="End"
FontAttributes="Bold"
FontSize="Medium"
Text="{Binding weight}" />
<Label HorizontalOptions="Start" Grid.Row="3"
VerticalOptions="End"
FontAttributes="Bold"
FontSize="Medium"
Margin="2"
Text="{Binding price}" />
<Button Text="Add TO Cart" Grid.Row="4" BackgroundColor="Coral" TextColor="WhiteSmoke" Clicked="Button_Clicked_1" />
</Grid>
</Frame>
</StackLayout>
</DataTemplate>
</controls:FlowListView.FlowColumnTemplate>
</controls:FlowListView>
and my logic is :
private async void Button_Clicked_1(object sender, EventArgs e)
{
if (((ListView)sender).SelectedItem == null)
return;
var myList = (ListView)sender;
var myProuct= (myList.SelectedItem as ProductDetail);
}
the sender of a Button Click event will be a BUTTON, not the ListView containing the button
private async void Button_Clicked_1(object sender, EventArgs e) {
// the sender of a button click event is a BUTTON
var btn = (Button)sender;
var myProduct = (ProductDetail)btn.BindingContext;
}
You could go with regular data binding way with viewmodel, or you can try this
Button Text="Add TO Cart" Grid.Row="4" BackgroundColor="Coral" TextColor="WhiteSmoke" Command="{Binding AddCommand}" CommandParameter = "{Binding .}"
But then you would need to edit the model building up ItemsGallery list.
public ICommand AddCommand { get; set; }
And when you are creating your objects
new Gallery
{
//your stuff
AddCommand = new Command<Gallery>(async (item) => await
AddItem(item))
})
private async Task AddItem(Gallery item)
{
//your implementation
}

How to binding the DataContext of an user-control?

I have a user-control like this:
<UserControl x:Class="IPAddressWPFUserControl.IPAddressControl"
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" BorderThickness="0" OverridesDefaultStyle="False" BorderBrush="{x:Null}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" x:Name="txtboxFirstPart" TextChanged="txtbox_TextChanged" MaxLength="3" BorderThickness="0" TabIndex="1" PreviewKeyDown="txtboxFirstPart_PreviewKeyDown" PreviewKeyUp="txtboxFirstPart_PreviewKeyUp" Width="31" />
<Label Content="." Grid.Column="1" x:Name="label1" VerticalContentAlignment="Bottom" HorizontalAlignment="Left" Background="White" />
<TextBox Grid.Column="2" x:Name="txtboxSecondPart" MaxLength="3" TextChanged="txtbox_TextChanged" BorderThickness="0" TabIndex="2" KeyDown="txtboxSecondPart_KeyDown" PreviewKeyUp="txtboxSecondPart_PreviewKeyUp" Margin="0" HorizontalAlignment="Left" Width="31"/>
<Label Content="." Grid.Column="3" Grid.Row="0" x:Name="label2" VerticalContentAlignment="Bottom" HorizontalAlignment="Left" Background="White" />
<TextBox Grid.Column="4" x:Name="txtboxThridPart" MaxLength="3" TextChanged="txtbox_TextChanged" BorderThickness="0" TabIndex="3" VerticalContentAlignment="Bottom" KeyDown="txtboxThridPart_KeyDown" PreviewKeyUp="txtboxThridPart_PreviewKeyUp" Width="31" HorizontalContentAlignment="Center" />
<Label Content="." Grid.Column="5" x:Name="label3" VerticalContentAlignment="Bottom" HorizontalAlignment="Left" Background="White" />
<TextBox Grid.Column="6" x:Name="txtboxFourthPart" MaxLength="3" TextChanged="txtbox_TextChanged" BorderThickness="0" TabIndex="4" VerticalContentAlignment="Bottom" HorizontalAlignment="Left" Width="31" HorizontalContentAlignment="Center" />
</Grid>
Added Text property to it in the code behind:
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(IPAddressControl),
new PropertyMetadata("0.0.0.0", new PropertyChangedCallback(OnTextPropertyChanged)));
private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
IPAddressControl o = d as IPAddressControl;
try
{
var value = e.NewValue as string;
var splitValues = new string[4];
if (value != null)
{
var splits = value.Split(new char[] { '.' }, StringSplitOptions.None);
Array.Copy(splits, splitValues, splits.Length);
}
o.txtboxFirstPart.Text = splitValues[0];
o.txtboxSecondPart.Text = splitValues[1];
o.txtboxThridPart.Text = splitValues[2];
o.txtboxFourthPart.Text = splitValues[3];
}
catch (Exception ex)
{
throw new Exception("Error in IP control see inner exception!", ex);
}
o.RaiseTextChanged(e);
}
public string Text
{
get { return (string)this.GetValue(IPAddressControl.TextProperty); }
set { this.SetValue(IPAddressControl.TextProperty, value); }
}
public event DependencyPropertyChangedEventHandler TextChanged;
protected virtual void RaiseTextChanged(DependencyPropertyChangedEventArgs e)
{
if (this.TextChanged != null)
{
this.TextChanged(this, e);
}
}
When I am using it in the MainWindow like this:
<GroupBox Name="gb_Tcp" DataContext="{Binding TcpCollection}">
<my:IPAddressControl x:Name="tb_IpAddress" Text="{Binding Path=IpAddress, ElementName=gb_tcp}"/>
<TextBox x:Name="tb_Test" Text={Binding Path=IpAddress, ElementName=gb_tcp}" />
</GroupBox>
The problem is when I try to set the value in a button click event:
private void btn_IpReset_Click(object sender, RoutedEventArgs e)
{
tb_IpAddress.Text = source.IpAddress; //This failed to change
tb_Test.Text= source.IpAddress; //This changed successfully
}
I suppose this is because the user-control didn't change the datacontext to the MainWindow's? Or what could be the problem is? Thanks in advance!
It's because you didn't use a BindingMode that will update source like TwoWay or OneWayToSource. So, after tb_IpAddress.Text = source.IpAddress, the binding you have set will be overwrite by the local value. tb_Test.Text= source.IpAddress work because TextBox.Text's default binding mode is TwoWay.

Xamarin Forms - Prism bound properties - Rendering issue

Git: https://github.com/jimmyt1988/Test
I'm running on desktop windows 10 pc on UWP Local device "emulator"
I have a deep integer property in my view model that gets incremented by a button command.
When i do, the number disapears from the screen, and then if i resize my application, it will render correctly again.
What's happening?
It seems to work on the Android emulator.
Code
public DelegateCommand<FoodGroupModel> SubtractFromAmountEatenCommand { get; private set; }
...
SubtractFromAmountEatenCommand = new DelegateCommand<FoodGroupModel>((foodGroup) => SubtractFromAmountEaten(foodGroup));
...
public void SubtractFromAmountEaten(FoodGroupModel foodGroup)
{
if(foodGroup.AmountEaten != 0)
{
foodGroup.AmountEaten--;
}
}
...
public class FoodGroupModel : BindableBase
{
private int _amountEaten;
public int AmountEaten
{
get { return _amountEaten; }
set { SetProperty(ref _amountEaten, value); }
}
}
XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="...Views.MealPage">
<StackLayout>
<Label Text="{Binding Meal.Number}"/>
<ListView x:Name="FoodGroupsListView" ItemsSource="{Binding Meal.FoodGroups}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" TextColor="#bababa" Text="Group"></Label>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding Title}" />
<Label Grid.Row="0" Grid.Column="2" TextColor="#bababa" Text="Qty"></Label>
<Label Grid.Row="0" Grid.Column="3" Text="{Binding AmountEaten}" />
<Button Grid.Row="0" Grid.Column="4"
Command="{Binding Source={x:Reference FoodGroupsListView}, Path=BindingContext.UndoAmountEatenByOneCommand}"
CommandParameter="{Binding}"
Text="✖"></Button>
<Button Grid.Row="0" Grid.Column="5"
Command="{Binding Source={x:Reference FoodGroupsListView}, Path=BindingContext.SubtractFromAmountEatenCommand}"
CommandParameter="{Binding}"
Text="✔"></Button>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
When i do, the number disapears from the screen, and then if i resize my application, it will render correctly again.
You might run into an issue: The changed notification of property binding won't work well(May be related to rerender) inside Xamarin ListView, Please report it in here: Bugzilla
In Windows runtime platform(Win/WP 8.1 & UWP), we have to use a workaround to temporarily avoid this:
private void RefreashFoodGroupModel()
{
if (Device.OS == TargetPlatform.Windows || Device.OS == TargetPlatform.WinPhone)
{
//var index = Meal.FoodGroups.IndexOf(foodGroup);
//Meal.FoodGroups.RemoveAt(index);
//Meal.FoodGroups.Insert(index, foodGroup);
var t = Meal.FoodGroups;
Meal.FoodGroups = new System.Collections.ObjectModel.ObservableCollection<FoodGroupModel>();
foreach (var item in t)
{
Meal.FoodGroups.Add(item);
}
}
}
Call the above method to refresh data after data change:
public void SubtractFromAmountEaten(FoodGroupModel foodGroup)
{
if(foodGroup.AmountEaten != 0)
{
foodGroup.AmountEaten--;
RefreashFoodGroupModel();
}
}
public void UndoAmountEatenByOne(FoodGroupModel foodGroup)
{
if (foodGroup.AmountEaten != foodGroup.Quantity)
{
foodGroup.AmountEaten++;
RefreashFoodGroupModel();
}
}
This workaround will cause the refresh of ListView items.

Resources