I want add item to tabcontrol with dynamic - c#

I'm making a WPF Application with MVVM pattern.
It's that I click a button many times and if I click Subbutton, it shows SubWindow with many Tabs.
Tab count is the same to click times.
But I want contain items in one Tab.
And click times is not the same always.
How should edit my code?
//view
<Grid>
<Button Content="CountUp" HorizontalAlignment="Left" Height="76" Margin="72,57,0,0" VerticalAlignment="Top" Width="135" Click="OnClickCountUp"/>
<Button Content="OpenSubWindow" HorizontalAlignment="Left" Height="74" Margin="269,202,0,0" VerticalAlignment="Top" Width="123" Click="OnClicOpenSubWindow"/>
<Label Content="Count : " HorizontalAlignment="Left" Height="28" Margin="254,73,0,0" VerticalAlignment="Top" Width="53"/>
<Label Content="{Binding CountVal}" HorizontalAlignment="Left" Height="28" Margin="307,73,0,0" VerticalAlignment="Top" Width="67"/>
</Grid>
//ViewModel
public class MainViewModel : INotifyPropertyChanged
{
private string count;
public string CountVal
{
get { return count; }
set
{
count = value;
NotifyPropertyChanged("CountVal");
}
}
public ObservableCollection<TabItemData> TabItems { get; set; } = new ObservableCollection<TabItemData>();
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
public class TabItemData
{
public string Header { get; set; }
public ObservableCollection<CheckBox> Content { get; set; }
}
//Codebehind
public partial class MainWindow : Window
{
private MainViewModel mViewmodel;
int count = 0;
public MainWindow()
{
InitializeComponent();
mViewmodel = new MainViewModel();
this.DataContext = mViewmodel;
}
private void OnClicOpenSubWindow(object sender, RoutedEventArgs e)
{
Window1 window1 = new Window1(mViewmodel);
window1.Show();
}
private void OnClickCountUp(object sender, RoutedEventArgs e)
{
count++;
ObservableCollection<CheckBox> items = new ObservableCollection<CheckBox>();
for (int i = 0; i <= count; i++)
{
CheckBox checkBox = new CheckBox();
checkBox.IsChecked = false;
checkBox.Content = count.ToString();
items.Add(checkBox);
}
mViewmodel.CountVal = count.ToString();
mViewmodel.TabItems.Add(new TabItemData() { Header = count.ToString(), Content = items });
}
}
//SubWindow's View
<Grid>
<TabControl ItemsSource="{Binding TabItems}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<CheckBox Content="{Binding Content}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
//SubWindow's Codebehind
public partial class Window1 : Window
{
public Window1(MainViewModel pMainViewModel)
{
InitializeComponent();
this.DataContext = pMainViewModel;
}
}
And there are supplements.
#I want use the checkbox as item in Tab. So I don't want change as possibly.
#If I can, I want add Tabs each 5 items. If you give me with that code, I'm very glad. (For Example, page1 contains item1, 2, 3, 4 and 5. page2 contains item6, 7... and so on.)

Related

How to send gridview selected row data to another window with textboxes in wpf using mvvm

I have tried a bunch of solutions about this problem on google but none seem to be helpful.
I have a button on every row which when clicked open a new window with textboxes. This window should display the selected row cells data.
I load the datagrid from mysql database.
VIEW
textboxes (XML) for second window
<Label Content="{Binding sFirstName, Mode=OneWay }" /> <Label Content="{Binding sLastName, Mode=OneWay }" />
Datagrid
<DataGrid ItemsSource="{Binding Path=MM}" SelectionMode="Extended" SelectedItem="{Binding SelectedItem}" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=sFirstName}" />
<DataGridTextColumn Binding="{Binding Path=sLastName}" />
</DataGrid.Columns>
MODEL
public class MM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string PropertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName)); }
private string _sFirstName, _sLastName;
public string sFirstName { get { return _sFirstName; } set { if (_sFirstName != value) { _sFirstName = value; OnPropertyChanged("sFirstName"); } } }
public string sLastName { get { return _sLastName; } set { if (_sLastName != value) { _sLastName = value; OnPropertyChanged("sLastName"); } } }
public DataRowView SelectedRow
{
get { return SelectedRow; }
set { SelectedRow = value; OnPropertyChanged("SelectedItem"); }
}
}
VIEW MODEL
Public class MV : INotifyPropertyChanged
{
private ICommand cmdLoad;
public ICommand CmdLoad { get { if (cmdLoad == null) cmdLoad = new RelayCommand(p => OnLoad()); return cmdLoad; } }
private void OnLoad() { Load(); }
public ObservableCollection<FinTuitionM> finTuitionM { get; set; }
public ClrIdVMD()
{
Load();
}
public void Load()
{
}
}
Code behind (cs)
public partial class Home : Window
{
MV mv;
public Home()
{ InitializeComponent();
mv = new MV(); DataContext = mv;
}
}
You seem to be very confused, so I have prepared a small example of what I think you are trying to achieve.
I am guessing that you want to have a main view that is essentially read only, and you intend to use a popup to make changes. On this basis the View Model for the main window does not need to implement INotifyPropertyChanged. So a simple View Model would look like this:
public class MV
{
public ObservableCollection<MM> MMs { get; set; }
private ICommand cmdShowDetails;
public ICommand CmdShowDetails
{
get
{
if (cmdShowDetails == null) cmdShowDetails = new RelayCommand(p => ShowDetails());
return cmdShowDetails;
}
}
public void ShowDetails()
{
var detVM = new DetailsVM(SelectedItem);
var dets = new DetailsWindow(detVM);
dets.ShowDialog();
}
public MV()
{
MMs = new ObservableCollection<MM>
{
new MM{sFirstName = "Mickey", sLastName = "Mouse"},
new MM{sFirstName = "Donald", sLastName = "Duck"},
new MM{sFirstName = "Roger", sLastName = "Rabbit"},
};
}
public MM SelectedItem { get; set; }
}
Notice that for demonstration purposes, I have loaded the ObservableCollection with some dummy data. In your case, this is replaced with data from the database.
The MM class that this refers to then looks something like this:
public class MM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent(string propertyName)
{
if (PropertyChanged != null)
{
var e = new PropertyChangedEventArgs(propertyName);
PropertyChanged(this, e);
}
}
private string firstName;
public string sFirstName
{
get { return firstName; }
set
{
if (firstName == value)
{
return;
}
firstName = value;
RaisePropertyChangedEvent("sFirstName");
}
}
private string lastName;
public string sLastName
{
get { return lastName; }
set
{
if (lastName == value)
{
return;
}
lastName = value;
RaisePropertyChangedEvent("sLastName");
}
}
}
Notice that SelectedItem is in the View Model (MV) and is an object of class MM, so that when the second window is opened, the ShowDetails command can pass the selected details.
This therefore calls for a new very simple view model for the second (details) window:
public class DetailsVM
{
public MM Detail { get; set; }
public DetailsVM(MM detail)
{
Detail = detail;
}
}
The main window grid xaml now looks like this:
<Grid>
<DockPanel>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<Button Content="Show Details" Command="{Binding CmdShowDetails}"></Button>
</StackPanel>
<DataGrid ItemsSource="{Binding MMs}" SelectedItem="{Binding SelectedItem}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding sFirstName}" />
<DataGridTextColumn Header="Last Name" Binding="{Binding sLastName}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Grid>
Notice here that I only have one button at the bottom of the window to transfer the details. This is because the details come from the selected item, which is the highlighted row.
The code behind is simply:
public partial class MainWindow : Window
{
private MV _mV;
public MainWindow()
{
InitializeComponent();
_mV = new MV();
DataContext = _mV;
}
}
Finally the xaml for the second (details) window
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40*"/>
<RowDefinition Height="40*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70*"/>
<ColumnDefinition Width="200*"/>
</Grid.ColumnDefinitions>
<Label Content="First Name" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBox Text="{Binding Detail.sFirstName}" Grid.Column="1" Grid.Row="0" Width="150" Height="25" HorizontalAlignment="Left" />
<Label Content="Last Name" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBox Text="{Binding Detail.sLastName}" Grid.Column="1" Grid.Row="1" Width="150" Height="25" HorizontalAlignment="Left" />
</Grid>
Notice here that the binding is to Detail.sFirstName and Detail.sLastName. The DataContext is a DetailsVM object, which has a property Detail of type MM, hence sFirstName and sLastName are sub-properties of Detail.
This window also has a very simple code behind:
public partial class DetailsWindow : Window
{
private DetailsVM _details;
public DetailsWindow(DetailsVM details)
{
_details = details;
DataContext = _details;
InitializeComponent();
}
}
If you now run this, you will find that changes made in the second window are automatically reflected back into the main window. In practice you will probably want Save and Cancel buttons in the second window.
I hope the above is sufficient to point you in the right direction!

Binding several buttons to individual items in an observable collection

If I have an ObservableCollection in one of my classes. In my code behind my view I have an object of this class and use it as the DataBinding
this.DataContext = MyCustomClass;
in the xaml code of the view I want to bind several buttons to items in the Observable collection. Something like this:
<Button x:Name="Bid_Price_10" Grid.Row="0" Content="{Binding myObservableCollection[0].Price, Mode=OneWay}" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" UseLayoutRounding="True" Padding="0"/>
<Button x:Name="Bid_Price_11" Grid.Row="1" Content="{Binding myObservableCollection[1].Price, Mode=OneWay}" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" UseLayoutRounding="True" Padding="0"/>
At the moment this is not working, am I missing something ?
EDIT: Create full code to demo what I am trying to do:
So I have a Coffee class:
class Coffee
{
public int price { get; set; }
}
I have a drinks class that holds a list of coffees:
class Drinks
{
public List<Coffee> CoffeeList;
public Drinks()
{
CoffeeList = new List<Coffee>();
for (int i = 0; i < 10; i++)
{
Coffee c = new Coffee();
c.price = i;
CoffeeList.Add(c);
}
this.startCoffeePriceUpdateThread();
}
private void UpdateCofffeePrice()
{
while (true)
{
Thread.Sleep(1000);
foreach (var c in CoffeeList)
{
c.price++;
}
}
}
public void startCoffeePriceUpdateThread()
{
Thread coffeeThread = new Thread(new ThreadStart(UpdateCofffeePrice));
coffeeThread.Start();
}
}
my main window code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Drinks ourDrinks = new Drinks();
this.DataContext = ourDrinks;
}
}
and my xaml code:
<Grid x:Name="Grid" HorizontalAlignment="Left" Height="193" Margin="77,31,0,0" VerticalAlignment="Top" Width="315">
<Button x:Name="Button" Content="{Binding CoffeeList[0].Price}" HorizontalAlignment="Left" Margin="49,25,0,0" VerticalAlignment="Top" Width="75" Height="28"/>
</Grid>
So the problem is that I am not seeing anything in the button. At the moment I am not using INotifyPropertyChange as I have been advised it would not be needed.
As Clemens suggested: if everything is fixed, you won't need ObservableCollection nor PropertyChanged notification. The following code should be sufficient:
public class Stuff
{
public string Price { get; set; }
}
public class myCustomClass
{
public List<Stuff> myCollection { get; set; }
}
public partial class MainWindow : Window
{
public myCustomClass myCustomInstance = new myCustomClass();
public MainWindow()
{
InitializeComponent();
myCustomInstance.myCollection = new List<Stuff>();
myCustomInstance.myCollection.Add(new Stuff() { Price = "1200$" });
myCustomInstance.myCollection.Add(new Stuff() { Price = "5.5$" });
this.DataContext = myCustomInstance;
}
}
And the simplified XAML
<Button Content="{Binding myCollection[0].Price, Mode=OneWay}"/>
<Button Content="{Binding myCollection[1].Price, Mode=OneWay}" />
NB: I specified an instance of myCustomClass as the DataContext. If you really need to bind it to the class, let me know and I will update the code.

Filling a ListBox from two TextBoxes with DataBinding

I have a ListBox I want to fill with data from two TextBoxesby clicking a Button. I think the problem comes from the differents textblock i have in my listbox. Here is what i want in image :
TheUI
The MainWindow.xaml of my listbox :
<ListBox x:Name="listBox"
ItemsSource="{Binding Issues}" Grid.Column="1" HorizontalAlignment="Left" Height="366" VerticalAlignment="Top" Width="453" Margin="0,0,-1,0">
<StackPanel Margin="3">
<DockPanel >
<TextBlock FontWeight="Bold" Text="Issue:"
DockPanel.Dock="Left"
Margin="5,0,10,0"/>
<TextBlock Text=" " />
<TextBlock Text="{Binding Issue}" Foreground="Green" FontWeight="Bold" />
</DockPanel>
<DockPanel >
<TextBlock FontWeight="Bold" Text="Comment:" Foreground ="DarkOrange"
DockPanel.Dock="Left"
Margin="5,0,5,0"/>
<TextBlock Text="{Binding Comment}" />
</DockPanel>
</StackPanel>
</ListBox>
My MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public sealed class ViewModel
{
public ObservableCollection<Issue> Issues { get; private set; }
public ViewModel()
{
Issues = new ObservableCollection<Issue>();
}
}
private void addIssue_Click(object sender, RoutedEventArgs e)
{
var vm = new ViewModel();
vm.Issues.Add(new Issue { Name = "Jon Skeet", Comment = "lolilol" });
DataContext = vm;
InitializeComponent();
}
}
My Issue.cs :
public sealed class Issue
{
public string Name { get; set; }
public string Comment { get; set; }
}
I follow this tutorial but i don't want to implement a Database :
Tuto
I also try to use this stackoverflow question
The error i have is 'System.InvalidOperationException' The Items collection must be empty to use ItemsSource
But not sure this is the heart of the problem.
Remove whatever you have inserted between <ListBox> and </ListBox>, as it is treated as part of Items collection.
Instead shift that content between <ListBox.ItemTemplate>...</ListBox.ItemTemplate>.
You don't need to update Context and InitializeComponent every time, atleast to your case.
public partial class MainWindow : Window
{
ViewModel vm = new ViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = vm;
}
public sealed class ViewModel
{
public ObservableCollection<Issue> Issues { get; private set; }
public ViewModel()
{
Issues = new ObservableCollection<Issue>();
}
}
private void addIssue_Click(object sender, RoutedEventArgs e)
{
vm.Issues.Add(new Issue { Name = "Jon Skeet", Comment = "lolilol" });
}
}

Selecting all CheckBoxes in ListBox not displayed properly

If I press a button "Check All" all CheckBoxes in a ListBox should be selected and added to a list where all checked items are stored. The problem is that only the visible checkboxes are updated properly.
Here is my CheckBoxListItem class:
public class Cbli : INotifyPropertyChanged
{
private string _name;
private Boolean _isChecked;
public string Name
{
get { return _name; }
set { _name = value; OnPropertyChanged("Name"); }
}
public bool IsChecked
{
get { return _isChecked; }
set { _isChecked = value; OnPropertyChanged("IsChecked"); }
}
public override string ToString()
{
return string.Format("Name: {0}, IsChecked: {1}", _name, _isChecked);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
<Window x:Class="ListBoxBuggy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:listBoxBuggy="clr-namespace:ListBoxBuggy"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}" WindowStartupLocation="CenterScreen">
<Window.Resources>
<DataTemplate x:Key="CheckBoxListItemTemplateNew" DataType="listBoxBuggy:Cbli">
<CheckBox Name="CheckBox"
IsChecked="{Binding IsChecked}"
Checked="Update"
Unchecked="Update"
FontSize="14">
<TextBlock Text="{Binding Name}" FontSize="14"/>
</CheckBox>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox HorizontalAlignment="Left" Height="300" VerticalAlignment="Top" Width="168"
ItemsSource="{Binding MyItemList}"
ItemTemplate="{StaticResource CheckBoxListItemTemplateNew}"
/>
<ListBox HorizontalAlignment="Left" Height="290" Margin="297,10,0,0" VerticalAlignment="Top" Width="195"
ItemsSource="{Binding CheckedItems}"
/>
<Button Content="Check All" HorizontalAlignment="Left" Margin="173,10,0,0" VerticalAlignment="Top" Width="75" Click="Check_All"/>
<Button Content="Uncheck All" HorizontalAlignment="Left" Margin="173,52,0,0" VerticalAlignment="Top" Width="75" Click="Uncheck_All"/>
</Grid>
</Window>
And the code behind:
public partial class MainWindow : Window
{
public ObservableCollection<Cbli> MyItemList { get; set; }
public ObservableCollection<Cbli> CheckedItems { get; set; }
public MainWindow()
{
// add dummy data
MyItemList = new ObservableCollection<Cbli>();
CheckedItems = new ObservableCollection<Cbli>();
for (int i = 0; i < 20; i++)
{
Cbli cbli = new Cbli
{
Name = "Test " + i,
IsChecked = i < 5 || i > 15
};
MyItemList.Add(cbli);
if (cbli.IsChecked)
CheckedItems.Add(cbli);
}
InitializeComponent();
}
private void Update(object sender, RoutedEventArgs e)
{
CheckBox selectedCheckbox = (CheckBox)sender;
Cbli cbli = (Cbli)selectedCheckbox.DataContext;
if (cbli.IsChecked)
CheckedItems.Add(cbli);
else
CheckedItems.Remove(cbli);
}
private void Check_All(object sender, RoutedEventArgs e)
{
foreach (Cbli cbli in MyItemList)
cbli.IsChecked = true;
}
private void Uncheck_All(object sender, RoutedEventArgs e)
{
foreach (Cbli cbli in MyItemList)
cbli.IsChecked = false;
}
}
After scrolling down, so all 20 items on the left list are visible and clicking then the "check all" button is working pretty well, but I don't know why.
Can someone please tell me what is wrong with that implementation? Checking/unchecking a single CheckBox is working, but the Check/Uncheck all buttons aren't working properly.
The comment from Blam (setting VirtualizingStackPanel.VirtualizationMode="Standard" was nearly the solution.
Add VirtualizingStackPanel.IsVirtualizing="False":
<ListBox HorizontalAlignment="Left" Height="300" VerticalAlignment="Top" Width="168"
ItemsSource="{Binding MyItemList}"
ItemTemplate="{StaticResource CheckBoxListItemTemplateNew}"
VirtualizingStackPanel.IsVirtualizing="False" />
This solved the problem (at least for me)

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