Toggle List Box Display In WPF - c#

I have a List Box in my WPF app. Here is the xaml code:
<ListBox Grid.Row="4" Grid.Column="1" Visibility="{Binding lbIsVisible}">
<ListBoxItem>
<CheckBox>
<TextBlock>CITRUS EXPRESS</TextBlock>
</CheckBox>
</ListBoxItem>
<ListBoxItem>
<CheckBox>
<TextBlock>APL CALIFORNIA</TextBlock>
</CheckBox>
</ListBoxItem>
<ListBoxItem>
<CheckBox>
<TextBlock>IS JAPAN</TextBlock>
</CheckBox>
</ListBoxItem>
</ListBox>
<CheckBox Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" x:Name="chkSelectVessel" Checked="chkSelectVessel_Checked">
<TextBlock Text="Select Vessel"></TextBlock>
</CheckBox>
I'm trying to toggle the visibility of the list box.
Here is the C# code.
public partial class ConfigSetting : Window
{
public string lbIsVisible { get; set; }
public ConfigSetting()
{
InitializeComponent();
DataContext = this;
lbIsVisible = "Hidden";
}
private void chkSelectVessel_Checked(object sender, RoutedEventArgs e)
{
this.lbIsVisible = "Visible";
}
}
But it doesn't seem to work. Can any one point where I'm going wrong?

You should use INotifyPropertyChanged Interface like this:
public partial class ConfigSetting : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string lbIsVisible;
public string LbIsVisible
{
get { return lbIsVisible; }
set
{
if (lbIsVisible != value)
{
lbIsVisible = value;
OnPropertyChanged("LbIsVisible");
}
}
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public ConfigSetting()
{
InitializeComponent();
LbIsVisible = "Hidden";
DataContext = this;
}
private void chkSelectVessel_Checked(object sender, RoutedEventArgs e)
{
LbIsVisible = "Visible";
}
private void ChkSelectVessel_OnUnchecked(object sender, RoutedEventArgs e)
{
LbIsVisible = "Hidden";
}
}
And in the XAML bind to LbIsVisible property:
<ListBox Visibility="{Binding LbIsVisible}">
Also add Unchecked event to your CheckBox :
<CheckBox Grid.Row="3" Grid.Column="1" VerticalAlignment="Center"
x:Name="chkSelectVessel" Checked="chkSelectVessel_Checked" Unchecked="ChkSelectVessel_OnUnchecked">

Related

Databinding to an Object property fails, to the parent it is working

I tried to bind a property to a nested object, but it fails.
I have taken a look at those questions, but i think i made another mistake somewhere else. Maybe someone can give i hind.
WPF: How to bind to a nested property?
binding to a property of an object
To upper slider/textbox has a correct binding while the lower one fails to do so.
I have two sliders with corrosponding textboxes:
<StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox Text="{Binding Path= boundnumber, Mode=TwoWay, FallbackValue='binding failed'}" ></TextBox>
<Slider Value="{Binding Path= boundnumber, Mode=TwoWay}" Width="500" Maximum="1000" ></Slider>
</StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" DataContext="{Binding Path=myDatarow}">
<TextBox Text="{Binding Path= boundnumber, Mode=TwoWay, FallbackValue='binding failed'}" ></TextBox>
<Slider Value="{Binding Path= boundnumber, Mode=TwoWay}" Width="500" Maximum="1000" ></Slider>
</StackPanel>
</StackPanel>
Code behind:
public partial class MainWindow : INotifyPropertyChanged
{
public MainWindow()
{
DataContext = this;
InitializeComponent();
}
private int _boundnumber;
public int boundnumber
{
get { return _boundnumber; }
set
{
if (value != _boundnumber)
{
_boundnumber = value;
OnPropertyChanged();
}
}
}
Datarow myDatarow = new Datarow(11);
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
class Datarow : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
public Datarow()
{
}
public Datarow(int number)
{
boundnumber = number;
}
private int _boundnumber;
public int boundnumber
{
get { return _boundnumber; }
set
{
if (value != _boundnumber)
{
_boundnumber = value;
OnPropertyChanged();
}
}
}
}
You need to expose your myDatarow into a public property like your boundnumber.
private DataRow _myDatarow = new DataRow(11);
public DataRow myDataRow
{
get { return _myDatarow; }
}
And just an additional advice.
It's better to separate your DataContext class from the MainWindow.

ComboBox Selected Item not updating

Problem
I am trying to bind a ComboBox's SelectedItem to a custom class but this does not update when the property is changed.INotifyPropertyChanged is implemented.
The DataContext
The DataContext is a custom class which contains many properties, but an extract of this is below. You can see it implements INotifyPropertyChanged and this called when the two properties are changed.
public class BctsChange : INotifyPropertyChanged
{
#region declarations
private byContact _Engineer;
public byContact Engineer
{
get { return _Engineer; }
set
{
_Engineer = value;
NotifyPropertyChanged("Engineer");
OnEngineerChanged();
}
}
private BctsSvc.DOSets _LeadingSet;
public BctsSvc.DOSets LeadingSet
{
get { return _LeadingSet; }
set { _LeadingSet = value; NotifyPropertyChanged("LeadingSet"); }
}
#endregion
#region INotify
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public BctsChange()
{
Engineer = new byContact(Environment.UserName);
}
private void OnEngineerChanged()
{
if (Engineer != null)
{
BctsSvc.DOSets leadSet = GetLeadingSetFromDeptCode(Engineer.DeptCode);
if (leadSet == null) return;
LeadingSet = leadSet;
}
}
private static BctsSvc.DOSets GetLeadingSetFromDeptCode(string DeptCode)
{
BctsSvc.BctsServiceSoapClient svc = new BctsSvc.BctsServiceSoapClient();
BctsSvc.DOSets setX = svc.GetSetFromDeptCode(DeptCode);
return setX;
}
}
The Window XAML
I have several controls on the window, but to keep the code simple I believe the following extract will suffice.
<Window x:Class="MyNamespace.wdSubmit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:MyNamespace"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
x:Name="ucReqForm"
Title="wdSubmit" >
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<GroupBox Header="Engineer Details" Name="grpOwnerDetails" >
<StackPanel Orientation="Vertical">
<Grid VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="35"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding Engineer.FullName, FallbackValue='Please select an engineer by clicking →', Mode=OneWay}" Margin="5,0" IsEnabled="True" FontStyle="Italic" />
<Button Content="{StaticResource icoSearch}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="1" Height="23" Name="btnSelectEngineer" Margin="0,0,5,0" HorizontalAlignment="Stretch" ToolTip="Search for an engineer responsible" Click="btnSelectEngineer_Click" />
</Grid>
<ComboBox Height="23" x:Name="ddSet2" Margin="5,0" ItemsSource="{Binding LeadingSets, Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" SelectedItem="{Binding LeadingSet, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,NotifyOnTargetUpdated=True}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding SetName}" ToolTip="{Binding HelpInfo}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<my:LabelledDropdown Height="23" x:Name="ddSet" Margin="5,0" ItemsSource="{Binding LeadingSets, Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" SelectedItem="{Binding LeadingSet, Mode=TwoWay,NotifyOnTargetUpdated=True,NotifyOnSourceUpdated=True}" Label="e.g. BodyHardware">
<my:LabelledDropdown.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding SetName}" ToolTip="{Binding HelpInfo}"/>
</DataTemplate>
</my:LabelledDropdown.ItemTemplate>
</my:LabelledDropdown>
</StackPanel>
</GroupBox>
</StackPanel>
</Window>
The above extract contains:
A Label that contains a contact's name, and a button to search for a contact, bound to the FullName of the Engineer
A ComboBox that contains departments within the company, bound to an ObservableCollection<DOSets>, which contains a list of departments
Two ComboBoxes, one which is a custom one and the other which is temporary to ensure the bug is not within the control. These are Databound to LeadingSet
Window Code Behind
In the code behind I set the DataContext to CurrentChange. When the user wants to select a different Engineer then this will update the selected department for the engineer in CurrentChange.
When the user changes the engineer, the data binding for the engineer is updated, but the selected department (Leading Set) isn't.
//Usings here
namespace MyNamespace
{
public partial class wdSubmit : Window, INotifyPropertyChanged
{
private BctsSvc.BctsServiceSoapClient svc;
private BctsChange _CurrentChange;
public BctsChange CurrentChange
{
get { return _CurrentChange; }
set { _CurrentChange = value; OnPropertyChanged("CurrentChange"); }
}
private List<BctsSvc.DOSets> _LeadingSets;
public List<BctsSvc.DOSets> LeadingSets
{
get
{
return _LeadingSets;
}
}
public wdSubmit()
{
InitializeComponent();
svc = new BctsSvc.BctsServiceSoapClient();
_LeadingSets = svc.GetLeadSets().ToList();
OnPropertyChanged("LeadingSets");
this._CurrentChange = new BctsChange();
this.DataContext = CurrentChange;
CurrentChange.PropertyChanged += new PropertyChangedEventHandler(CurrentChange_PropertyChanged);
}
void CurrentChange_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged("CurrentChange");
OnPropertyChanged(e.PropertyName);
}
private void btnSelectEngineer_Click(object sender, RoutedEventArgs e)
{
byContact newContact = new frmSearchEngineer().ShowSearch();
if (newContact != null)
{
CurrentChange.Engineer = newContact;
PropertyChanged(CurrentChange, new PropertyChangedEventArgs("LeadingSet"));
PropertyChanged(CurrentChange.LeadingSet, new PropertyChangedEventArgs("LeadingSet"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(CurrentChange, new PropertyChangedEventArgs(propertyName));
}
}
}
I've realised the problem may be due to the LeadingSet, returned when the engineer is changed, being a different instance to that in the ObservableCollection.

Change item checkbox on ListBox selection change

I have a ListBox created by ItemTemplate and Binding
<controls:PanoramaItem Header="{Binding AppResources.SettingsSubpage2, Source={StaticResource LocalizedStrings}}" HeaderTemplate="{StaticResource HeaderTemplate}">
<Grid>
<ListBox x:Name="DayOfWeekSelector" ItemTemplate="{StaticResource DayOfWeekTemplate}" ItemsSource="{Binding DayOfWeekElementList}" Foreground="{StaticResource AppForegroundColor}" LostFocus="DayOfWeekSelector_LostFocus" HorizontalAlignment="Left" Width="420" />
</Grid>
</controls:PanoramaItem>
Template code:
<phone:PhoneApplicationPage.Resources>
<!--- ... --->
<DataTemplate x:Key="DayOfWeekTemplate">
<Grid Height="65" Width="332">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding IsActive, Mode=TwoWay}" Tag="{Binding}" d:LayoutOverrides="Width, Height" BorderBrush="{StaticResource AppBackgroundColor}" Background="{StaticResource ScheduleBackgroundAccentsColor}" Grid.Column="0" Unchecked="CheckBox_Unchecked" />
<StackPanel Grid.Column="1" Orientation="Horizontal">
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" d:LayoutOverrides="Width"/>
<TextBlock Text="{Binding TaskCounter, Mode=OneWay, Converter={StaticResource DayOfWeekCounter}}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0,0,0"/>
</StackPanel>
</Grid>
</DataTemplate>
<!--- ... --->
And it's working fine. I've got all my items on the list. Checkboxes are binded to appropriate elements (clicking on it is changing proper value).
But by default ListBox can be also selected. Selection high-light TextBox binded to Name but don't change CheckBox (binded to IsActive). How can I tie item selection changing to checkbox state changing (in Silverlight)?
Edit:
public partial class SettingsPage : PhoneApplicationPage, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public List<DayOfWeekElement> DayOfWeekList
{
get
{
return CyberSyncPlanBase.Instance.DayOfWeekElementList;
}
set
{
CyberSyncPlanBase.Instance.DayOfWeekElementList = value;
NotifyPropertyChanged("DayOfWeekList");
}
}
public SettingsPage()
{
InitializeComponent();
DayOfWeekSelector.DataContext = CyberSyncPlanBase.Instance;
}
private void DayOfWeekSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DayOfWeekElement dowe = (DayOfWeekElement) DayOfWeekSelector.SelectedItem;
if (dowe != null)
dowe.IsActive = (dowe.IsActive) ? false : true;
}
And in singleton INotifyPropertyChanged i've implemented in the same way:
private List<DayOfWeekElement> dayOfWeekElementList;
public List<DayOfWeekElement> DayOfWeekElementList
{
get { return dayOfWeekElementList; }
set
{
dayOfWeekElementList = value;
RecalcWeekTasks();
NotifyPropertyChanged("DayOfWeekElementList");
}
}
Bottom class:
public class DayOfWeekElement
{
public string Name { get { return this.DayOfWeek.ToStringValue(); } }
public bool IsNotEmpty { get { return (TaskCounter > 0); } }
public int TaskCounter { get; set; }
public bool IsActive { get; set; }
public DayOfWeek DayOfWeek { get; set; }
}
I think you could use the SelectedItem property of the ListBox control.
A possible implementation could be this:
Subscribe to the event SelectedIndexChanged of the ListBox.
Get the selected item.
For the selected item, change its IsActive property to true.
This works if the interface INotifyPropertyChanged is implemented in your data class.
E.g.:
public class DayOfWeekElement : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool isActive = false;
public bool IsActive {
get
{
return this.isActive;
}
set
{
if (value != this.isActive)
{
this.isActive= value;
NotifyPropertyChanged("IsActive");
}
}
}
}

Why TextBlock Text is not updating in ViewModel?

I am trying to post some values to the next screen through XML serialization and Isolated Storage. Values are posted from textbox and also from textBlock to the next screen's textBlocks with button click event. But the TextBlock's text is not posted to the next screen, only the textBox text is posted. If I debug and check, XML shows as "" with no string loadedinto it. It's also not binding as well. Why?
//MainPage.xaml
<StackPanel>
<Button Margin="10"
Content="Simple Sample"
Name="btnSimple"
Click="btnSimple_Click">
</Button>
<TextBlock TextWrapping="Wrap" Text="{Binding FirstName, Mode=TwoWay}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding MyText, Mode=TwoWay}"/>
</StackPanel>
//MainPage.xaml.cs
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using System.IO;
using System.IO.IsolatedStorage;
using System.Text;
using System.Xml.Serialization;
namespace WPIsolatedStorage
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
private LastUser _User = new LastUser();
private const string USER_KEY = "LastUser";
public MainPage()
{
InitializeComponent();
}
private void GetUser()
{
string xml;
xml = IsolatedStorageSettings.ApplicationSettings[USER_KEY].ToString();
using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(xml)))
{
XmlSerializer serializer = new XmlSerializer(typeof(LastUser));
_User = (LastUser)serializer.Deserialize(ms);
}
}
private void btnSimple_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/PageSimple.xaml", UriKind.Relative));
}
private void PhoneApplicationPage_Loaded_1(object sender, RoutedEventArgs e)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(USER_KEY))
GetUser();
this.DataContext = _User;
}
}
}
//LastUser.cs
using System.ComponentModel;
namespace WPIsolatedStorage
{
public class LastUser : INotifyPropertyChanged
{
#region INotifyPropertyChanged Event
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Private Variables
private string mFirstName = string.Empty;
private string mTextBlock = string.Empty;
#endregion
#region Public Variables
public string FirstName
{
get { return mFirstName; }
set
{
if (mFirstName != value)
{
mFirstName = value;
RaisePropertyChanged("FirstName");
}
}
}
public string MyText
{
get { return this.mTextBlock; }
set
{
this.mTextBlock = value;
this.RaisePropertyChanged("MyText");
}
}}
}
//SeconPage.xaml
<TextBox Grid.Column="1"
Grid.Row="0"
Text="{Binding FirstName, Mode=TwoWay}"
Name="txtFirstName" />
<TextBlock Grid.Column="1" Name="MyTextBlock" HorizontalAlignment="Left" Margin="12,178,0,-224" Grid.Row="4" TextWrapping="Wrap" Text="{Binding MyText, Mode=TwoWay}" VerticalAlignment="Top" Height="93" Width="191" FontSize="36"/>
There is a typo in you binding expression. Should be
<TextBlock Grid.Column="1" .... Text="{Binding MyText}" ../>
instead of
<TextBlock Grid.Column="1" .... Text="{Binding Mytext}" ../>
My second assumption is: you use a simple binding in your code
<TextBlock TextWrapping="Wrap" Text="{Binding MyText, Mode=TwoWay}"/>
But in Windows Phone the binding works only after you unfocused control. You can find a discussion and few solutions here:
TextBox Binding TwoWay Doesn't Update Until Focus Lost WP7
Try This.
Code snippet[C#]:
public class Data : INotifyPropertyChanged
{
private int customerID;
public int CustomerID
{
get { return customerID; }
set { customerID = value; OnPropertyChanged("CustomerID"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
Code snippet[XAML]:
<TextBlock Content="{Binding CustomerID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

How to use an observable collection and notifyproperty changed

I am new to wpf and i am currently trying to play with grid and adding subtracting,removing elements to a db table which eventually binds to a grid.
So select from grid, update observable collection, refresh.
I am failing to understand how can i use change notifications of observable collection.
Here is my code
Class which binds to grid
public class students
{
ObservableCollection<GetStudents_Result> stdb = new ObservableCollection<GetStudents_Result>();
//public event NotifyCollectionChangedEventHandler CollectionChanged;
public students()
{
AbcdEntities abcdEnt=new AbcdEntities();
List<GetStudents_Result> studentColl = abcdEnt.GetStudents().ToList();
foreach (var item in studentColl)
{
stdb.Add(item);
}
}
//public void onCollectionChange(object sender,NotifyCollectionChangedEventHandler e)
//{
//}
public ObservableCollection<GetStudents_Result> std {get {return stdb;}}
}
my xaml.
<Canvas>
<TextBox Height="23" Canvas.Top="5" Canvas.Left="10" HorizontalAlignment="Left" Margin="10,10,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
<TextBox Height="23" Canvas.Top="30" Canvas.Left="10" HorizontalAlignment="Left" Margin="10,10,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" />
<Button Canvas.Left="90" Canvas.Top="65" Content="Remove" Click="button2_Click" Height="23" Name="button2" Width="75" />
<Button Canvas.Left="10" Canvas.Top="65" Content="Save" Height="23" Name="button1" Width="75" Click="button1_Click" />
<ListView Name="listviewStudents" Canvas.Top="100" ItemsSource="{Binding std}" SelectionChanged="ListView_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="fname" DisplayMemberBinding="{Binding Path=fname}"></GridViewColumn>
<GridViewColumn Header="lname" DisplayMemberBinding="{Binding Path=lname}"></GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=address}"></GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=phno}"></GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=radio}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Canvas>
my code behind
public MainWindow()
{
InitializeComponent();
students std = new students();
this.DataContext = std;
}
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
GetStudents_Result selectedItem = listviewStudents.SelectedItem as GetStudents_Result;
textBox1.Text = selectedItem.fname;
textBox2.Text = selectedItem.lname;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
GetStudents_Result selecteditem = listviewStudents.SelectedItem as GetStudents_Result;
selecteditem.fname = textBox1.Text;
selecteditem.lname = textBox2.Text;
listviewStudents.Items.Refresh();
}
private void button2_Click(object sender, RoutedEventArgs e)
{
listviewStudents.Items.Remove(listviewStudents.SelectedItem);
listviewStudents.Items.Refresh();
}
}
}
pardon for any stupid mistakes..
There a a coulpe of problems here, you should not have to touch the UI controls from the code behind, you should be using data binding.
Here is a working example of model binding based on your post.
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
// set the DataContext to the code in this window
this.DataContext = this;
// create youe Student model
StudentModel = new students();
}
// Create a public property of your student Model
private students _studentModel;
public students StudentModel
{
get { return _studentModel; }
set { _studentModel = value; NotifyPropertyChanged("StudentModel"); }
}
// create a public property to use as the selected item from your models "std" collection
private GetStudents_Result _selectedResult;
public GetStudents_Result SelectedResult
{
get { return _selectedResult; }
set { _selectedResult = value; NotifyPropertyChanged("SelectedResult"); }
}
private void button2_Click(object sender, RoutedEventArgs e)
{
// if you want to remove an item you just have to remove it from
// the model, the INotifyPropertyChanged interface will notify the UI
// to update, no need to call Refresh, same works for Add etc
StudentModel.std.Remove(SelectedResult);
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
Now in the xaml we can bind the ListView to your StudentModel collection and the SelectedResult
<ListView ItemsSource="{Binding StudentModel.std}" SelectedItem="{Binding SelectedResult}" >
And for the TextBoxes you can bind to the SelectedResult so it will update the details for you
Note: In this example it updates the SelectedResult when the text changes, you can change this as you wish.
<TextBox Text="{Binding SelectedResult.Fname, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding SelectedResult.Lname, UpdateSourceTrigger=PropertyChanged}" />
So now when you select an item from the ListView these TextBoxes will be populated, and when they are changed the SelectedResult item will be changed.
Now, for adding and removing Items in your ListView, you just have to add and remove from your StudentModelcollection (StudentModel.std).
private void button2_Click(object sender, RoutedEventArgs e)
{
StudentModel.std.Remove(SelectedResult);
}
Note: This event handler should be an ICommand binding, but i will let your search for that :)
Here is a Full example tha hopefully helps explaining the basics of WPF MVVM
Code:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
StudentModel = new students();
}
private students _studentModel;
public students StudentModel
{
get { return _studentModel; }
set { _studentModel = value; NotifyPropertyChanged("StudentModel"); }
}
private GetStudents_Result _selectedResult;
public GetStudents_Result SelectedResult
{
get { return _selectedResult; }
set { _selectedResult = value; NotifyPropertyChanged("SelectedResult"); }
}
private void button2_Click(object sender, RoutedEventArgs e)
{
StudentModel.std.Remove(SelectedResult);
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
public class students
{
public students()
{
std = new ObservableCollection<GetStudents_Result>();
for (int i = 0; i < 100; i++)
{
std.Add(new GetStudents_Result { Fname = "FirstName" + i, Lname = "LasrName" + i });
}
}
public ObservableCollection<GetStudents_Result> std { get; set; }
}
public class GetStudents_Result : INotifyPropertyChanged
{
private string _fname;
private string _lname;
public string Fname
{
get { return _fname; }
set { _fname = value; NotifyPropertyChanged("Fname"); }
}
public string Lname
{
get { return _lname; }
set { _lname = value; NotifyPropertyChanged("Lname"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
Xaml:
<Canvas>
<TextBox Text="{Binding SelectedResult.Fname, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding SelectedResult.Lname, UpdateSourceTrigger=PropertyChanged}" />
<Button Canvas.Left="90" Canvas.Top="65" Content="Remove" Click="button2_Click" Height="23" Name="button2" Width="75" />
<Button Canvas.Left="10" Canvas.Top="65" Content="Save" Height="23" Name="button1" Width="75" />
<ListView Name="listviewStudents" Canvas.Top="100" ItemsSource="{Binding StudentModel.std}" SelectedItem="{Binding SelectedResult}" >
<ListView.View>
<GridView>
<GridViewColumn Header="fname" DisplayMemberBinding="{Binding Path=Fname}"></GridViewColumn>
<GridViewColumn Header="lname" DisplayMemberBinding="{Binding Path=Lname}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Canvas>
I hope this info helps :)
Okay first, I apologize if I do a poor job answering this. It's my first attempt.
So it looks like you've got the right idea, and most of what you've got will work. But it looks like you may have forgotten to implement INotifyPropertyChanged. And you might just consider using something like List<GetStudent_Result> instead, there is a lot less overhead than an ObservableCollection because you'll be implementing the NotifyPropertyChanged stuff yourself.
public class students : INotifyPropertyChanged
{
#region PropertyChanged EventHandler
public event PropertyChangedEventHandler PropertyChanged;
void NotifyPropertyChanged(String Property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(Property));
}
#endregion
private List<GetStudents_Result> stdb;
public List<GetStudents_Result> std
{
get { return stdb; }
set { stdb = value; NotifyPropertyChanged("std"); }
}
...

Categories