WPF MVVM Clear textbox bound to Listview SelectedItem - c#

I am trying to learn about C# mvvm and wpf, so i decided to make a simple project(a book&readers managing application for a library) and now i am a little lost so i would really appreciate some help.
In my view i have a listview displaying the readers, and a bunch of textboxes bound to the selected item of the listview(name, adress,etc).
The listview is bound to an observable collection of readers created from a database table(Readers) with Linq2SQL.
Below the textboxes i have a few buttons (Clear/Add/Save/Delete).
The problems i am having are that the "selected item" of the listview, seems null if i try to execute some commands when i click the buttons.
when i click the clear button, if i have a breakpoint on the selected item(reader), it shows that it gets null/empty spaced, but the textboxes dont clear;
If in the Clear method in use the SelectedReader property, and assign empty spaces to its attributes, the selected item in the listview also clears(because its bound to Reader's FullName property)
i have other problems on adding a new reader, and saving changes, and i assume its because of wrong linq queries but i hope i can fix the current ones and move on afterwards.
What should i do?
ViewModel
public class MainWindowViewModel : ViewModelBase
{
private Reader selectedReader;
private ObservableCollection<Reader> readerList;
public MainWindowViewModel()
{
SelectedReader = new Reader()
{
FullName = "",
SerialNumber = "",
IdNumber = "",
Adress = "",
AltContactMethods = ""
};
BookDBDataContext rdb = new BookDBDataContext();
ReadersList = new ObservableCollection<Reader>(rdb.Readers);
AddR = new TblQryCommand(AddToDb);
EditR = new TblQryCommand(EditToDb);
DeleteR = new TblQryCommand(DeleteFromDb);
ClearR = new TblQryCommand(ClearReaderFields);
}
public TblQryCommand AddR { get; private set; }
public TblQryCommand EditR { get; private set; }
public TblQryCommand DeleteR { get; private set; }
public TblQryCommand ClearR { get; private set; }
//Reader List
public ObservableCollection<Reader> ReadersList
{
get { return readerList; }
set
{
if (readerList != value)
{
readerList = value;
RaisePropertyChanged();
}
}
}
public Reader SelectedReader
{
get { return selectedReader; }
set
{
if (selectedReader != value)
{
selectedReader = value;
RaisePropertyChanged();
}
}
}
public void AddToDb()
{
BookDBDataContext db = new BookDBDataContext();
Reader r = new Reader
{
FullName = SelectedReader.FullName,
SerialNumber = SelectedReader.SerialNumber,
IdNumber = SelectedReader.IdNumber,
Adress = SelectedReader.Adress,
AltContactMethods = SelectedReader.AltContactMethods
};
db.Readers.InsertOnSubmit(r);
db.Readers.Context.SubmitChanges();
}
public void DeleteFromDb()
{
}
public void EditToDb()
{
}
public void ClearReaderFields()
{
SelectedReader = new Reader
{
Id = 0,
FullName = string.Empty,
SerialNumber = string.Empty,
IdNumber = string.Empty,
Adress = string.Empty,
AltContactMethods = string.Empty
};
}
View:
<ListView Name="listviewReaders" ItemsSource="{Binding ReadersList}" SelectedItem="{Binding SelectedReader,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="140" Height="180" Margin="10,68,492,281">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FullName}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBox x:Name="txtBxFullName" HorizontalAlignment="Left" Height="22" Margin="211,68,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.FullName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<TextBox x:Name="txtBxSerialNumber" HorizontalAlignment="Left" Height="22" Margin="211,95,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.SerialNumber, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<TextBox x:Name="txtBxIdNumber" HorizontalAlignment="Left" Height="22" Margin="211,122,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.IdNumber, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<TextBox x:Name="txtBxAdress" HorizontalAlignment="Left" Height="22" Margin="211,149,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.Adress, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<TextBox x:Name="txtBxAltContactMethods" HorizontalAlignment="Left" Height="22" Margin="211,176,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.AltContactMethods, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<Button x:Name="btnReader_Clear" Content="Clear" Command="{Binding ClearR}" HorizontalAlignment="Left" Margin="211,228,0,0" VerticalAlignment="Top" Width="75"/>
<Button x:Name="btnReader_Save" Content="Save" Command="{Binding EditR}" HorizontalAlignment="Left" Margin="291,228,0,0" VerticalAlignment="Top" Width="75"/>
<Button x:Name="btnReader_Add" Content="Add New" Command="{Binding AddR}" HorizontalAlignment="Left" Margin="371,228,0,0" VerticalAlignment="Top" Width="75"/>
<Button x:Name="btnReader_Delete" Content="Delete" Command="{Binding DeleteR}" HorizontalAlignment="Left" Margin="451,228,0,0" VerticalAlignment="Top" Width="75"/>

Have you tried to set the Binding of the Text-Property of your textboxes to your ViewModel's SelectedReader-Property directly?
So instead of writing this:
<TextBox x:Name="txtBxFullName" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.FullName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" ... />
you would write:
<TextBox x:Name="txtBxFullName" Text="{Binding Path=SelectedReader.FullName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" ... />

Related

Inputted Items sometimes appear empty in Data grid

I have ItemsControl and a DataGrid in a WPF UserControl. this is how it looks like
when the "Add to card" button is pressed a ViewModel instance is added to ObservableCollection bound to the DataGrid.
<ItemsControl
ItemsSource="{Binding Meals}"
x:Name="MealList"
Margin="5">
<ItemsControl.ItemTemplate>
<DataTemplate>
<components:MealCardCustomer
BorderBrush="OrangeRed"
BorderThickness="5px"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<DataGrid
HorizontalAlignment="Stretch"
IsReadOnly="True"
Background="Orange"
x:Name="OrderedMeals"
SelectionMode="Single"
ItemsSource="{Binding OrderedMeals, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
SelectedIndex="{Binding SelectedOrderedMeal, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"
FontSize="26"
Grid.Column="0"
Grid.Row="0"
Margin="5"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name, Mode=OneWay}" Header="Name" />
<DataGridTextColumn Binding= "{Binding Price, Mode=OneWay}" Header="Price" />
<DataGridTextColumn Binding="{Binding Ingredients, Mode=OneWay}" Header="Ingredients" />
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
The problem is that sometimes when I add new items it appears like an empty column.
I tried to add a button which refreshes the data grid but when pressed it makes the all of the items blank.
Also I've wrapped the DataGrid in a ScrollViewer with a horizontal scroll which for some reason doesn't work.
That's the ViewModel of the View
private string? address;
public string? Address
{
get { return address; }
set { address = value; OnPropertyChaneg(nameof(Address)); }
}
private int selectedOrderedMeal = -1;
public int SelectedOrderedMeal
{
get { return selectedOrderedMeal; }
set { selectedOrderedMeal = value; OnPropertyChaneg(nameof(SelectedOrderedMeal)); }
}
private ObservableCollection<MealCardCustomerViewModel> meals;
public ObservableCollection<MealCardCustomerViewModel> Meals
{
get { return meals; }
set { meals = value; }
}
private ObservableCollection<MealCardCustomerViewModel> orderedMeals;
public ObservableCollection<MealCardCustomerViewModel> OrderedMeals
{
get { return orderedMeals; }
set { orderedMeals = value; OnPropertyChaneg(nameof(OrderedMeals)); }
}
public BaseCommand RemoveCommand { get; }
public BaseCommand FinishOrderCommand { get; }
public NavigateCommand NavigateToCustomerListOfOtders { get; }
public BaseCommand LoadMealsCommand { get; }
public CustomerOrderingViewModel(NavigationService customerListOfOrdersNavigationService, NavigationService helpNavigationService, IMealService mealService)
: base(helpNavigationService, mealService)
{
Meals = new ObservableCollection<MealCardCustomerViewModel>();
OrderedMeals = new ObservableCollection<MealCardCustomerViewModel>();
RemoveCommand = new RemoveMeal(this);
FinishOrderCommand = new FinishOrder(this, customerListOfOrdersNavigationService);
NavigateToCustomerListOfOtders = new NavigateCommand(customerListOfOrdersNavigationService);
LoadMealsCommand = new LoadMeals<CustomerOrderingViewModel>(this);
}
public static CustomerOrderingViewModel LoadViewModel(NavigationService customerListOfOrders, NavigationService helpNavigationService, IMealService mealService)
{
CustomerOrderingViewModel viewModel = new CustomerOrderingViewModel(customerListOfOrders, helpNavigationService, mealService);
viewModel.LoadMealsCommand.Execute(null);
return viewModel;
}
public override void LoadMealsList(List<Meal> meals)
{
Meals.Clear();
foreach (var meal in meals)
{
Meals.Add(new MealCardCustomerViewModel(meal,this));
}
}
That the Views which act like ItemTemplates for the ItemsControl
<Image
Source="{Binding MealImage, Converter ={StaticResource imageConverter}, Mode=TwoWay, TargetNullValue=DefaultImage}"
Stretch="Uniform"/>
<DockPanel
Grid.Row="1"
VerticalAlignment="Center"
Margin="5">
<TextBlock
FontSize="20"
Margin="5"
Text="Name :"/>
<TextBox
Text="{Binding Name,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
FontSize="20"
Margin="5"/>
</DockPanel>
<DockPanel
Grid.Row="2"
VerticalAlignment="Center"
Margin="5">
<TextBlock
FontSize="20"
Margin="5"
Text="Price :"/>
<TextBox
Text="{Binding Price, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:f2}}"
FontSize="20"
Margin="5"/>
</DockPanel>
<DockPanel
Grid.Row="3"
VerticalAlignment="Center"
Margin="5">
<TextBlock
FontSize="20"
Margin="5"
Text="Ingredients:"/>
<TextBox
Text="{Binding Ingredients, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
FontSize="20"
Margin="5"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
/>
</DockPanel>
<Button
Command="{Binding AddToCardCommand}"
Background="OrangeRed"
Grid.Row="4"
Margin="10 5 10 5"
Content="Add to cart"
FontSize="20"/>
and that's the command that adds the item to the ObservableCollection
private CustomerOrderingViewModel customerOrderingViewModel;
private MealCardCustomerViewModel mealCardCustomerViewModel;
public AddToCard(CustomerOrderingViewModel customerOrderingViewModel, MealCardCustomerViewModel mealCardCustomerViewModel)
{
this.customerOrderingViewModel = customerOrderingViewModel;
this.mealCardCustomerViewModel = mealCardCustomerViewModel;
}
public override void Execute(object? parameter)
{
customerOrderingViewModel.OrderedMeals.Add(mealCardCustomerViewModel);
}
The problem was with the images in the objects which are non existing right now and so they are null.
For some reason the null value cause infinite loop in the converter and so the view models could not load the properties of the entity but the collection could read that the count was changed thus displaying the empty rows.
The way you add items to the cart is not thread safe.
Immagine the AddToCart() being called wich will update your customerOrderingViewModel and mealCardCustomerViewModel. Then immagine that before Execute is called, some other thread changes customerOrderingViewModel or mealCardCustomerViewModel. This could result in Execute() adding the wrong (or a Null) meal to your order.
If that is the reason for your error, the following code shoud solve it:
public AddToCard(CustomerOrderingViewModel customerOrderingViewModel, MealCardCustomerViewModel mealCardCustomerViewModel)
{
customerOrderingViewModel.OrderedMeals.Add(mealCardCustomerViewModel);
this.customerOrderingViewModel = customerOrderingViewModel;
this.mealCardCustomerViewModel = mealCardCustomerViewModel;
}
If you dont need customerOrderingViewModel and mealCardCustomerViewModel in the class owning AddToCart(), you could even spare those variables completely.
Side note:
If you dont plan on changing the observable collections but only their content, you can simply declare them as public fiels and not as propertys. The setter of the propertys wil only be accessed when thwo whole ObservableCollection object is changed but not if its content is changed. PropertyChanged notifications for changes inside the ObservableCollection are handlled by the ObservableCollection implementation.

I can't add an Entity Framework entry. System.ArgumentNullException: "The value cannot be null. Parameter name: entity"

There is a WPF form containing 8 textboxes.
<StackPanel Grid.Column="2">
<TextBox Margin="5" Width="100" Text="{Binding SelectedOrder.OrderCode}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.ClientID}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.RouteCode}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.DriverID}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.TCCode}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.Date}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.StartDate}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.EndDate}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<Button Margin="50" Width="100" Content="Create"
Command="{Binding AddCommand}"
/>
</StackPanel>
There is a ViewModel class that implements the transfer of data from the view to the model
public class OrderViewModel : INotifyPropertyChanged
{
private ObservableCollection<Order> orderList; //list of records in the Order table
private Order selectedOrder; // specific entry in Order
private TransportCompanyEntities transportCompanyEntities; // context?
public Order SelectedOrder
{
get { return selectedOrder; }
set
{
selectedOrder = value;
OnPropertyChanged(nameof(SelectedOrder));
}
}
public ObservableCollection<Order> OrderList
{
get { return orderList; }
set
{
orderList = value;
OnPropertyChanged(nameof(OrderList));
}
}
public OrderViewModel()
{
transportCompanyEntities = new TransportCompanyEntities();
Load Orders();
}
private void LoadOrders()
{
OrderList = new ObservableCollection<Order>(transportCompanyEntities.Order);
}
private RelayCommand addCommand;
public RelayCommand AddCommand
{
get
{
return addCommand ??
(addCommand = new RelayCommand(obj =>
{
transportCompanyEntities.Order.Add(SelectedOrder);
transportCompanyEntities.SaveChanges();
}));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class RelayCommand{}
When the button is clicked, an entry should be created, but an error occurs
How can i fix it?
System.ArgumentNullException: "Value cannot be null. Parameter name: entity"
I understand that I am trying to add an empty entry, but it is not clear to me why it is not created when the button is clicked.

Checkbox Event not trigerred in Listview UWP

I'm actually developping an UWP app who's reading Excel data, and display it on a form. Every Excel sheet are represented with RadioButton, and when the user click on a RadioButton, I update a ListView with the corresponding data.
Every item of the ListView have different data, and 2 checkboxes. This checkboxes can have the state "true" or "false", and if the user need to change the state, I want to modify his value
But the problem is, there is no event triggered with all the checkboxes when I check them. I tried to search and try to make my own template, but without success.
All the data are stored in a class :
public class REFERENCES
{
public int AI_ID { get; set; }
public int ID_poste { get; set; }
public string reference { get; set; }
public string designation { get; set; }
public bool avance { get; set; }
public bool jour { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public REFERENCES(int ai_id, int id_poste, string ref_, string des_, string avance_, string jour_)
{
AI_ID = ai_id;
ID_poste = id_poste;
reference = ref_;
designation = des_;
if(jour_ != null)
{
jour = true;
}
else
{
jour = false;
}
if (avance_ != null)
{
avance = true;
}
else
{
avance = false;
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And this is my ListView :
<ListView x:Name="ListViewData" SelectionMode="None" HorizontalAlignment="Center" Height="412" VerticalAlignment="Top" Width="650" Margin="0,218,0,0" >
<ListView.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Height="35" Margin="0,0,0,0" VerticalAlignment="Center" >
<TextBlock Text="AI_ID" Width="0" Visibility="Collapsed" />
<TextBlock Text="Désignations" FontSize="20" Width="300" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="Références" FontSize="20" Width="150" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="Avance" FontSize="20" Width="100" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="Jour" FontSize="20" Width="100" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate x:DataType="ExcelLinkData:REFERENCES">
<StackPanel Orientation="Horizontal" >
<TextBlock Name="ItemAI_ID" Text="{x:Bind AI_ID}" Width="0" />
<TextBlock Name="ItemDesignation" Text="{x:Bind designation}" Width="300" FontSize="16" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center"/>
<TextBlock Name="ItemReference" Text="{x:Bind reference}" Width="150" FontSize="16" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" />
<Grid Width="100" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center">
<CheckBox Name="ItemAvance" IsChecked="{x:Bind avance}" Tag="{x:Bind AI_ID}" Checked="CHANGE_STATUS_REFERENCE"/>
</Grid>
<Grid Width="100" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center">
<CheckBox Name="ItemJour" IsChecked="{x:Bind jour}" Tag="{x:Bind AI_ID}" Checked="CHANGE_STATUS_REFERENCE"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The method "CHANGE_STATUS_REFERENCE" is the method where I want to change the state in my class.
I tried different solutions, but I'm not an expert in UWP, so if anyone got an advice, I'll take it !
Thanks in advance for your time !
Guillaume
In UWP, default mode for Binding is OneTime. And when you change property from viewmodel then no event is triggered. By changing Binding to OneWay / TwoWay (depending on your usage), viewmodel will trigger the event.
Change
IsChecked="{x:Bind jour}"
To
IsChecked="{x:Bind jour Mode=TwoWay}"
Change
<CheckBox Name="ItemAvance" IsChecked="{x:Bind avance}" Tag="{x:Bind AI_ID}" Checked="CHANGE_STATUS_REFERENCE"/>
to
<CheckBox Name="ItemAvance" IsChecked="{x:Bind avance}" Tag="{x:Bind AI_ID}" Command="{Binding CHANGE_STATUS_REFERENCE}"/>
Add a "Flip Function" to your class:
private void Flip()
{
this.avance = !this.avance;
}
Set up a RelayCommand:
RelayCommand _flipCommand = new RelayCommand(this.Flip);
and Implement CHANGE_STATUS_REFERENCE as an ICommand like so:
public ICommand CHANGE_STATUS_REFERENCE
{
get
{
return _flipCommand;
}
}

Is there a way to get the index of a item in the UWP toolkits PullToRefreshList?

Im trying to take the Id from a button that I binded to the button tag but when I try I get it in a method a null value error is thrown even though I can set the context and text and the Id will appear on screen fine.
So now im trying to mark the items in the list with a index so when the data template generates them I can easily call them and compare them to the ids in my c# code.
XAML for list:
<my:PullToRefreshListView
x:Name="RefreshListView"
MinWidth="200"
Margin="24"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Background="White"
OverscrollLimit="0.4"
PullThreshold="100"
IsPullToRefreshWithMouseEnabled="True">
<my:PullToRefreshListView.ItemTemplate >
<DataTemplate >
<StackPanel Name="ListPanel">
<TextBlock AutomationProperties.Name="IdTextBlock"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Id}"
TextWrapping="WrapWholeWords" />
<TextBlock AutomationProperties.Name="{Binding Name}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Name}"
TextWrapping="WrapWholeWords" />
<TextBlock AutomationProperties.Name="{Binding Sets}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Sets}"
TextWrapping="WrapWholeWords" />
<TextBlock AutomationProperties.Name="{Binding SetTime}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding SetTime}"
TextWrapping="WrapWholeWords" />
<StackPanel Orientation="Horizontal">
<Button Tag="{Binding Id}" Content="Delete" Click="DelButton_Click" Style="{StaticResource DrillButtons}" ></Button>
<Button Tag="{Binding Id}" Content="Update" Click="UpdateBtn_Click" Style="{StaticResource DrillButtons}" ></Button>
</StackPanel>
</StackPanel>
</DataTemplate>
</my:PullToRefreshListView.ItemTemplate>
<my:PullToRefreshListView.PullToRefreshContent>
<TextBlock FontSize="16"
Opacity="0.5"
Text="Pull down to refresh data" />
</my:PullToRefreshListView.PullToRefreshContent>
</my:PullToRefreshListView
These two buttons from the stack panel above is where im trying to bind the Id to retrieve later.
<StackPanel Orientation="Horizontal">
<Button Tag="{Binding Id}" Content="Delete" Click="DelButton_Click" Style="{StaticResource DrillButtons}" ></Button>
<Button Tag="{Binding Id}" Content="Update" Click="UpdateBtn_Click" Style="{StaticResource DrillButtons}" ></Button>
</StackPanel>
Heres the methods that take in the Id from the buttons:
//Update button
private async void NewSubmitBtn_Click(object sender, RoutedEventArgs e)
{
String Name = NewNameBox.Text;
String id = (String)((Button)sender).Content;
int Sets;
int Time;
bool successfullyParsedTime = int.TryParse(NewSetsBox.Text, out Time);
bool successfullyParsedSets = int.TryParse(NewTimeBox.Text, out Sets);
if (successfullyParsedSets)
{
Sets = Int32.Parse(NewSetsBox.Text);
}
if (successfullyParsedTime)
{
Time = Int32.Parse(NewTimeBox.Text);
}
await ctv.combatDrillsTable.UpdateDrill(id, Name, Sets, Time, catagory);
ppup.IsOpen = false;
var addSuccess = new MessageDialog("Drill Updated");
await addSuccess.ShowAsync();
}
Heres the data item code:
namespace UWPCombatApp
{
class DrillItem
{
public string Id { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "sets")]
public int Sets { get; set; }
[JsonProperty(PropertyName = "settime")]
public int SetTime { get; set; }
[JsonProperty(PropertyName = "style")]
public string Style { get; set; }
}
}
The delete popup I added:
// Delete button
private void DelButton_Click(object sender, RoutedEventArgs e)
{
delpup.Height = Window.Current.Bounds.Height;
delpup.IsOpen = true;
id = (((Button)sender).Tag).ToString();
}
The id is binded to this using tag and once they select yes the following function is called to delete the item from the database:
private async void YesBtn_Click(object sender, RoutedEventArgs e)
{
await ctv.combatDrillsTable.DeleteDrillAsync(id);
var addSuccess = new MessageDialog("Drill Deleted");
await addSuccess.ShowAsync();
}
Inside the eventHandler:
private async void NewSubmitBtn_Click(object sender, RoutedEventArgs e)
you are setting the value of the id variable to the Content of the button instead of the Tag.
Change :
String id = (String)((Button)sender).Content;
to this:
String id = (String)((Button)sender).Tag;
Make sure to call the right event handler because on the click event of the update button your are calling
the handler :
<Button Tag="{Binding Id}" Content="Update" Click="UpdateBtn_Click" Style="{StaticResource DrillButtons}" ></Button>
instead of
<Button Tag="{Binding Id}" Content="Update" Click="NewSubmitBtn_Click" Style="{StaticResource DrillButtons}" ></Button>
Best of luck!

How do I get databinding to work with null class?

I am developing a WPF application that is pretty much an application form. It has multiple text fields. This is my first application I am doing using the MVVM model so I am sure I am missing something. I have a lot of textboxes so the code I show will concentrate on four text field, the fourth field is suppose to total as the other three change. However the databinding I have is not executing. I cannot figure out why when I type a number into the textbox txbFamO the FamilyO get statement is not executed. Am I not binding correctly? Do I not have the class Applicant initialized correctly?
Here is my XAML:
<UserControl x:Class="ApplicationForm.Views.ApplicationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ApplicationForm"
xmlns:model="clr-namespace:ApplicationForm.Model"
xmlns:views="clr-namespace:ApplicationForm.Views"
xmlns:viewModel="clr-namespace:ApplicationForm.ViewModel"
mc:Ignorable="d"
Height="1100" Width="800" Background="#FFDAFDF2">
<Grid x:Name="grdAppForm">
<Grid x:Name="grdAppFormGrid" DataContext="{Binding Applicant}"
Height="881" Width="700" Margin="0,0,0,0">
<Label x:Name="lblFamilySize" Content="Family Size:" Height="28" Width="102" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="372,71,0,0" FontFamily="Arial" FontWeight="Bold" FontSize="16" />
<Label x:Name="lblFamO" Content="O:" Height="28" Width="27" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="471,71,0,0" FontFamily="Arial" FontWeight="Bold" FontSize="16"/>
<TextBox x:Name="txbFamO" Text="{Binding FamilyO, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="22" Width="20" HorizontalAlignment="Left"
VerticalAlignment="Top" Margin="496,71,0,0" FontFamily="Arial" FontSize="16"
FontWeight="Bold" BorderThickness="0,0,0,3" BorderBrush="Black" VerticalContentAlignment="Bottom"/>
<Label x:Name="lblFamA" Content="A:" Height="28" Width="25" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="516,71,0,0" FontFamily="Arial" FontWeight="Bold" FontSize="16"/>
<TextBox x:Name="tbxFamA" Text="{Binding FamilyA, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Height="22" Width="20" HorizontalAlignment="Left"
VerticalAlignment="Top" Margin="541,71,0,0" FontFamily="Arial" FontSize="16"
FontWeight="Bold" BorderThickness="0,0,0,3" BorderBrush="Black" VerticalContentAlignment="Bottom"/>
<Label x:Name="lblFamC" Content="C:" Height="28" Width="25" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="562,71,0,0" FontFamily="Arial" FontWeight="Bold" FontSize="16"/>
<TextBox x:Name="txtFamC" Text="{Binding FamilyC, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Height="22" Width="20" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="587,71,0,0" FontFamily="Arial" FontSize="16" FontWeight="Bold" BorderThickness="0,0,0,3" BorderBrush="Black" VerticalContentAlignment="Bottom"/>
<Label x:Name="lblEqual" Content="=" Height="28" Width="20" HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="611,71,0,0" FontFamily="Arial" FontWeight="Bold" FontSize="16"/>
<TextBox x:Name="tbxFamTot" Text="{Binding FamilyTotal,
Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Height="22" Width="30"
HorizontalAlignment="Left" VerticalAlignment="Top" Margin="634,71,0,0" FontFamily="Arial"
FontWeight="Bold" FontSize="16" BorderBrush="Black" BorderThickness="0,0,0,3" IsTabStop="False"
VerticalContentAlignment="Bottom"/>
</Grid>
</Grid>
My Model Code:
namespace ApplicationForm.Model
{
public class ApplicationModel
{
}
public class Applicant : INotifyPropertyChanged
{
private string familyO;
private string familyA;
private string familyC;
public string FamilyO
{
get { return familyO; }
set
{
if (familyO != value)
{
familyO = value;
RaisePropertyChanged("FamilyO");
RaisePropertyChanged("FamilyTotal");
}
}
}
public string FamilyA
{
get { return familyA; }
set
{
if (familyA != value)
{
familyA = value;
RaisePropertyChanged("FamilyA");
RaisePropertyChanged("FamilyTotal");
}
}
}
public string FamilyC
{
get { return familyC; }
set
{
if (familyC != value)
{
familyC = value;
RaisePropertyChanged("FamilyC");
RaisePropertyChanged("FamilyTotal");
}
}
}
public string FamilyTotal
{
get
{
return (Convert.ToInt16(familyO) + Convert.ToInt16(familyA) + Convert.ToInt16(familyC)).ToString();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
My ViewModel Code:
namespace ApplicationForm.ViewModel
{
class ApplicationViewModel : INotifyPropertyChanged
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/sheets.googleapis.com-dotnet-quickstart.json
static string[] Scopes = { SheetsService.Scope.Spreadsheets };
static string ApplicationName = "NB Food Pantry Application";
public RelayCommand LoadApplicantCommand
{
get;
set;
}
public RelayCommand ClearDataCommand
{
get;
set;
}
public RelayCommand PrintApplicantCommand
{
get;
set;
}
public RelayCommand CloseCommand
{
get;
set;
}
public Applicant applicants;
public ApplicationViewModel()
{
applicants = new Applicant();
PrintApplicantCommand = new RelayCommand(PrintApplicant);
ClearDataCommand = new RelayCommand(ClearApplicantData);
CloseCommand = new RelayCommand(CloseApp);
}
public ObservableCollection<Applicant> Applicants
{
get;
set;
}
}
}
I have figured out my issue. I didn't create an instance of Applicants and initialize the elements.

Categories

Resources