Update ListView using Linq to Sql Classes in WPF - c#

Im trying to do a simple program that adds data to the database through linq to sql, what im trying to achieve is when i send the data, the listview automatically update here's the behind-code
private DataClasses1DataContext DC = new DataClasses1DataContext();
private void Window_Loaded(object sender, RoutedEventArgs e) {
ListViewData.ItemsSource = DC.Persons;
}
private void Button_Click(object sender, RoutedEventArgs e) {
Person NewPerson = new Person() { Name = nametxt.Text, Address = addresstxt.Text };
DC.Persons.InsertOnSubmit(NewPerson);
DC.SubmitChanges();
}
XAML code
<ListView Name="ListViewData" HorizontalAlignment="Left" Height="238" Margin="10,72,0,0" VerticalAlignment="Top" Width="321">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Address" DisplayMemberBinding="{Binding Address}"/>
</GridView>
</ListView.View>
</ListView>
i read about the INotifyPropertyChanging, INotifyPropertyChanged but i think the code generated by Visual Studio when a Linq To Sql Class is added already implements them, but i'm not sure, i just started to use WPF

The ListView will not update itself automatically when the source collection changes unless the source collection implements INotifyCollectionChanged. If the source collection does not implement INotifyCollectionChanged then you will have to manually update the ItemsSource property. In your case, however, I do not think you can simply do this:
DC.SubmitChanges();
ListViewData.ItemsSource = DC.Persons;
I am pretty sure (not positive) that DC.Person will still refer to the same object after you call DC.SubmitChanges(). If you try to re-set the ItemsSource property to the same value it will not trigger a refresh.
If the DC.Persons has relatively few items then you could do this:
DC.SubmitChanges();
ListViewData.ItemsSource = DC.Persons.ToArray();
That will copy Persons to a new array and assign that array to the ListView's ItemsSource property. If you have thousands of items then you may want to find another solution; maybe the CollectionViewSource.

Related

Bind a checkbox in a listview to a class variable?

I would like to be able to get and set the state of a checkbox in a listview. I would like to either be able to automatically update MyListItems[row].myCheckedValue when the box is clicked by somehow binding in xaml (I know very little about binding) or to be able to loop through each list item by row and access the checkboxes in C#. I don't know how to approach either. I'm just starting out with WPF.
I Could also use Checked and Unchecked events, but I don't know how to retrieve the row of the list item the checkbox is in.
<ListView Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox x:Name="checkBox" Checked="itsChecked" Unchecked="itsUnchecked"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public List<myListItem> MyListItems;
...
listView.ItemsSource = MyListItems;
...
public class myListItem {
public bool myCheckedValue;
}
private void getCheckedItems() {
//Loop through listview rows and get checkbox state
//???
}
private void itsChecked(object sender, RoutedEventArgs e) {
//How can I get the row this checkbox is in??
}
something like
<GridViewColumn Header="Selected">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="chk" IsChecked="{Binding MyListItemsBoolField}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
assuming that your listView.ItemsSource = MyListItems; will stay
It should be as simple as binding IsChecked property of the CheckBox to a property on the ViewModel (you may need to add a new property if it doesn't already exist).

Automatically resize columns of wpf GridView

I've gone through a few posts with similar requirements but haven't found a fully working solution yet.
I have a GridView in a ListView with a few columns
<ListView x:Name="TheList" DockPanel.Dock="Top"
ItemsSource="{Binding Itemlist}"
SelectionMode="Extended">
<ListView.View>
<GridView>
....
<GridViewColumn x:Name="valueColumn" Header="Value" DisplayMemberBinding="{Binding ItemValue}" Width="150"/>
</GridView>
</ListView.View>
</ListView>
I set the model and sub to the model's property changing
_viewModel = new MyModel();
DataContext = _viewModel;
_viewModel.ItemValueChanged += RunResizeLogic; //ItemValueChanged gets emitted when the property changes
And then based on some solutions I found I attempt resizing the column
private void RunResizeLogic(object sender, EventArgs e)
{
ResizeGridViewColumn(valueColumn);
}
private void ResizeGridViewColumn(GridViewColumn col)
{
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
{
if (double.IsNaN(col.Width))
{
col.Width = col.ActualWidth;
}
col.Width = double.NaN;
}));
}
My resize logic gets called when the my ItemValue changes, however, the column is only resizing when ItemValue changes again.
So, if it's current size is 5. the ItemValue size changes to 10, my logic runs with ActualWidth==5, column remains the same size (5). The ItemValue size changes again to 2, logic runs ActualWidth==2 and the column resizes to 10.
What am I doing wrong? Thanks.
EDIT:
Some of the posts I've looked through
GridViewColumn Width Adjustment
WPF: GridViewColumn resize event

WPF ListView binding to the collection

I implemented a collection of Hyperlink elements using WPF:
var controlLinks = new List<Hyperlink>();
if (issueLinks != null)
{
foreach (var link in issueLinks)
{
var tempLink = new Hyperlink()
{
NavigateUri = new Uri(link.link)
};
controlLinks.Add(tempLink);
}
}
ListIssueLinks.ItemsSource = controlLinks;
Collections is successfuly filled, now I link ListIssueLinks view to this collection.
<ListView Name="ListIssueLinks" Height="100" >
<ListView.View>
<GridView>
<GridViewColumn/>
</GridView>
</ListView.View>
</ListView>
Here I've got a problem, the issue is I'm new to WPF and have no idea how properly implement formatting (for example, to present NavigateUri or Name only on UI) and implement generic handler for click on any element. Something like this:
private void Hyperlink_OnClick(object sender, RoutedEventArgs e)
{
var clickedLink = (Hyperlink) sender;
System.Diagnostics.Process.Start(clickedLink.NavigateUri.ToString());
}
I tried DataTemplate, tried a lot of other variants, googled really a lot, but still have no clue how to do that. Could you please suggest any easy and elegant solution?
DataTemplate is your best bet, here's how you could implement it in your case.
<ListView Name="ListIssueLinks" Height="100">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink NavigateUri="{Binding}" RequestNavigate="Link_RequestNavigate">
<TextBlock Text="{Binding}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then in your code behind, I would simply bind directly to your issueLinks (no need to build up HyperLinks in code).
List<string> issueLinks = new List<string>()
{
"http://www.google.com",
"http://www.stackoverflow.com",
};
ListIssueLinks.ItemsSource = issueLinks;
Then your RequestNavigate event handler needs to start your process
private void Link_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
I didnt fully understand what is your problem but i have two things that you should know that exist.
ObservableCollection
i think you should consider use it instead of a simple List because it has advantages if you need to bind the List to The View with your ListView for example. for more info read here: ObservableCollection Class
XAML side
the second thing i think you tried to explain is how to take properties and show them in your list view. this means you need to write it on the XAML side and explore about it farther, you can bind the properties after that with inotifypropertychanged if the data in the list is going to change with any reason.
hope i helped.

retrieve object from binding property wpf

Hello im trying to retrieve an object from a list of binding objects. Im using MVVM style
so i have a class name Channel. Channel has the following properties: string Name, string Label, int Id, int assignedLocation, etc..
I also have a XAML file named ChannelSetup.xaml in which there is a
<ListView x:Name="ListView">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Width="65" Header="Channel #">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox "Loaded="LineComboBox_OnLoaded"....
</GridViewColumn>
in my ChannelSetup.xaml.cs file i have something like this
this.AvailableChannelLines = new ObservableCollection<Channel>();
this.DataContext = this;
this.ListView.ItemsSource = this.AvailableChannelLines;
it does populate my list view correctly and everything is fine..
private void LineComboBox_OnLoaded(object sender, RoutedEventArgs e)
{
//// HERE I NEED TO GET THE CURRENT CHANNEL OBJECT
}
but when the LineComboBox_OnLoaded event gets called i want to be able to know/get the current channel object that's is being binded to. How can this be done or i need to use a different approach, methods or events??
DataContext of comboBox will point to the current channel.
private void LineComboBox_OnLoaded(object sender, RoutedEventArgs e)
{
Channel currentChannel = (sender as ComboBox).DataContext as Channel;
}

Draw resizable table in WPF

I mean how should I display my datastructure for I can work with it like with table?
I want to have a table with rows and columns can be dynamicaly added and removed, but in the rest is should looks like a table.
Now it's represented like IList>, because I should resize it, as I said before. But now i want to display it in DataGrid, and be able to have rows, coulmns, and work with "Cells". But i cannot bind it properly, it it does not display anything, only an empty cell for every row.
What should I do? Or mby use arrays and resize them after each row/column addition?
Please, advice.
Now I have this one:
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
var storage = new Storage();
storage.Data.Add(new DataRow("Bla-bla")
{
new DataEntity() {Text = "bla-bla", Forces = new[] {ForceEnum.AA}},
new DataEntity() {Text = "bla-bla", Forces = new[] {ForceEnum.UA}}
});
DataListView.DataContext = new StorageModel(storage);
}
public class StorageModel
{
public StorageModel()
{
}
public StorageModel(IStorage storage)
{
DataRowList = new ObservableCollection<DataRow>(storage.Data);
}
public ObservableCollection<DataRow> DataRowList
{
get;
set;
}
}
public class DataRow : IList<DataEntity>
{
public string Name { get; private set; }
private readonly List<DataEntity> _list = new List<DataEntity>();
...
_
<ListView ItemsSource="{Binding DataRowList}" Name="DataListView">
<ListView.ItemTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
i want be able to create something similar to this, but with 2-way binding...
You seem to be asking for TreeView and not ListView since you have a tree alike data structure.
If you do not want to use a TreeView I would suggest you to use a simple ListView with a small trick. That is you could explose an Expander which will add or remove items underneath parent with an indent to fake tree look and still all cells in column would be resized together.
Btw dont forgot to define columns
Here is how:
<ListView Margin="10" Name="lvUsers">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
<GridViewColumn Header="Mail" Width="150" DisplayMemberBinding="{Binding Mail}" />
</GridView>
</ListView.View>
</ListView>
If you wish to implement that expander trick behavior I would suggest you to listen to event OnExpanded and add or remove the needed rows.

Categories