Lazy/deferred loading of a CollectionViewSource? - wpf

When you create a CollectionViewSource in the Resources section, is the set Source loaded when the resources are initalized (i.e. when the Resources holder is inited) or when data is bound?
Is there a xamly way to make a CollectionViewSource lazy-load? deferred-load? explicit-load?

The answer is, that the CollectionViewSource does not initialize its Source property as long as not requested!
Here is my test example:
<Window
x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:WpfApplication2">
<Window.Resources>
<CollectionViewSource x:Key="mySource">
<CollectionViewSource.Source>
<src:Collection />
</CollectionViewSource.Source>
</CollectionViewSource>
</Window.Resources>
<!--ListView ItemsSource="{Binding Source={StaticResource mySource}}"/-->
</Window>
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Public Class Collection : Inherits ObservableCollection(Of String)
Public Sub New()
If Not DesignerProperties.GetIsInDesignMode(New DependencyObject) Then End
For i = 1 To 10
Add("Item " & i)
Next
End Sub
End Class
Result: the project shuts-down only when the ListView is uncommented.

Related

How to update database from DataGrid using Entity Framework

I am trying to use a CRUD Operations on Wpf DataGrid with Entity Framework.
Existing rows can successfully modified and when click save button changes are saved. When it comes to new rows the entity framework SaveChanges for some reason is not saving new rows. I thought that would be easy but I don't understand what am doing wrong here.
I have the following page in wpf
<Page x:Class="TaxGroupsListing"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:wendbooksVatRatSetup"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="TaxGroupsListing">
<Page.DataContext>
<local:TaxGroupListingVM x:Name="test"></local:TaxGroupListingVM>
</Page.DataContext>
<DockPanel >
<Button Margin="2" DockPanel.Dock="Top" Content="Load" Command="{Binding Path=LoadCmd}"></Button>
<Button Margin="2" DockPanel.Dock="Top" Content="Save" Command="{Binding Path=SaveCmd}"></Button>
<DataGrid IsSynchronizedWithCurrentItem="True" Margin="2" CanUserAddRows="True"
ItemsSource="{Binding Groups,UpdateSourceTrigger=PropertyChanged}">
</DataGrid>
</DockPanel>
And the ViewModel as shown here
Public Class TaxGroupListingVM : Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Sub notify()
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(String.Empty))
End Sub
Property Groups As New ObservableCollection(Of TaxGroup)
Property LoadCmd As New mycommad(AddressOf LoadData)
Property SaveCmd As New mycommad(AddressOf SaveData)
Private db As New SQlDataBaseEntities
Private Sub SaveData()
db.SaveChanges()
LoadData()
End Sub
Private Sub LoadData()
Dim qry = From g As TaxGroup In db.TaxGroups Select g
Groups = New ObservableCollection(Of TaxGroup)
For Each item In qry
Groups.Add(item)
Next
notify()
End Sub
End Class
When you add a new row, it's only adding a new item to the Groups collection, it's not adding the item to the DbContext.
When you add a new row, handle the CollectionChanged event of your Groups collection, and add the new items to the DbContext (something like db.TaxGroups.Add(newItem)). Then the db.SaveChanges should work fine.
(This probably should have been an answer to begin with, so adding it here instead of comment.)

Trying to bind a list of objects to a WPF datagrid control and seeing blank lines

I am stuck and need some help. I have spent a full day trying to sort this one out. I have read a lot of examples of how this should be done and it appears that I have done it correctly but clearly I have missed something. I have a blank form with one button and one datagrid. When I click the button I want to load a list of points into the datagrid control. The data must be getting loaded because I see three blank lines in the grid (no headers), but no data. Help please! Thanks!
Class MainWindow
Class Point
Public Inc As String
Public AZ As String
Public MD As String
Public TD As String
End Class
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
Dim mySurvey As New List(Of Point)
Dim myPoint1 As New Point
Dim myPoint2 As New Point
myPoint1.AZ = "1"
myPoint1.Inc = "2"
myPoint1.MD = "100"
myPoint1.TD = "98"
myPoint2.AZ = "10"
myPoint2.Inc = "20"
myPoint2.MD = "1000"
Point2.TD = "980"
mySurvey.Add(myPoint1)
mySurvey.Add(myPoint2)
dgSurvey.ItemsSource = mySurvey
End Sub
End Class
XAML
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Height="28" Margin="45,30,0,0" VerticalAlignment="Top" Width="57" Click="Button_Click"/>
<DataGrid x:Name="dgSurvey" HorizontalAlignment="Left" Margin="45,78,0,0" VerticalAlignment="Top" Height="172" Width="275"/>
</Grid>
For binding to work you should define properties in your Point class, not public fields.
This is explicitly stated in MSDN: Binding Sources Overview:
The properties you use as binding source properties for a binding must be public
properties of your class. Explicitly defined interface properties cannot be
accessed for binding purposes, nor can protected, private, internal,
or virtual properties that have no base implementation.
You cannot bind to public fields.

Events and Properties accessible from outside of UserControl MVVM

So, I have a UserControl named ApplicationForm. It has some TextBoxes and a Button. Each TextBox has a Binding. An example of it:
<xctk:WatermarkTextBox Watermark="PACAPIME" Text="{Binding NumPac}" Grid.Column="2" Grid.Row="2" />
Then, my View is bound to a ViewModel like this:
<UserControl x:Class="Verkooporder"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:vm="clr-namespace:Koala" mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1100">
<UserControl.Resources>
<vm:VerkooporderViewModel x:Key="VerkooporderViewModelDataSource"
d:IsDataSource="True"/>
</UserControl.Resources>
<UserControl.DataContext>
<Binding Source="{StaticResource VerkooporderViewModelDataSource}"/>
</UserControl.DataContext>
The corresponding property in my ViewModel is like this:
Private _oNumPac As String = ""
Public Property NumPac As String
Get
Return _oNumPac
End Get
Set(ByVal value As String)
_oNumPac = value
RaisePropertyChanged()
End Set
End Property
This is working great inside my UserControl. Now, I call my UserControl in my MainWindow:
<local:Verkooporder />
I want to be able to access the Property NumPac like <local:Verkooporder NumPac="" /> but this isn't working.
Also, how can I have access to the Button Command?
Public Shared _oNumPac As DependencyProperty = DependencyProperty.Register("NumPac",
GetType(String), GetType(VerkooporderViewModel), New PropertyMetadata(""))
Public Property NumPac As String
Get
Return GetValue(_oNumPac)
End Get
Set(value As String)
SetValue(_oNumPac, value)
End Set
End Property
But it doesn't show up when I try to type this:
<local:Verkooporder NumPac="Test" />
Notice that the properties are in the ViewModel of the UserControl, not the code behind View

DesignTime only error when trying to load an xml to a dataset

I've created a simple WPFApplication project that produce this error
This is the exact error:
Could not find file
'C:\Users\Andrei\AppData\Local\Microsoft\VisualStudio\11.0\Designer\ShadowCache\dj2szrx3.5nm\e412xqna.uj1\Locality.xml'. E:\BugDemo2\BugDemo2\MainWindow.xaml 7 9 BugDemo2
MainWindow.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="MainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<!--This is the line that Visual Studio says it produce the error -->
<local:MainWindowViewModel x:Key="MainWindowViewModelDataSource" d:IsDataSource="True"/>
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource MainWindowViewModelDataSource}}"/>
</Window>
MainWindowViewModel.vb
Imports System.Data
Imports System.IO
Public Class MainWindowViewModel
Shared ds As New DataSet("Locality")
Public Sub New()
MySub()
End Sub
Sub MySub()
'this is the line that actually gives the error
ds.ReadXml(
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly.Location) &
"\Locality.xml")
MsgBox(ds.Tables.Count)
End Sub
End Class
I have nothing in the code behind MainWindow.xaml.vb
Class MainWindow
End Class
The program does exactly what it is supposed to do, it loads Locality.xml to dataset correctly and shows how many tables are in it.
If I move the ds variable in another module, or in another class, as a shared property I get
Object reference not set to an instance of an object
also as a Designtime only error.
I understand that Visual Studio doesn't know if Locality.xml, but why does it care and how do I make this error go away?
Use protective code, and more debuggable since you can check the variable before executing ReadXml:
Sub MySub()
Dim path As String = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly.Location) &
"\Locality.xml"
If IO.File.Exists(path) Then
ds.ReadXml(path)
MsgBox(ds.Tables.Count)
End If
End Sub

wpf command custom control binding xaml

i'm building a Videoplayer custom control (Project called WpfCustomControlLibrary1) and want to add a Load Command.
This is what i have added in my class to get this Command:
Public Class VideoPlayer
Inherits Control
...
Public Shared ReadOnly LoadCommad As RoutedUICommand
....
Shared Sub New()
'This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
'This style is defined in Themes\Generic.xaml
DefaultStyleKeyProperty.OverrideMetadata(GetType(VideoPlayer), New FrameworkPropertyMetadata(GetType(VideoPlayer)))
LoadCommad = New RoutedUICommand("Load", "Load Video", GetType(VideoPlayer))
CommandManager.RegisterClassCommandBinding(GetType(VideoPlayer), New CommandBinding(LoadCommad, AddressOf OnLoadExecuted))
End Sub
...
And this is how i call it from my XAML:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomControlLibrary1">
.....
<Button Command="local:VideoPlayer.LoadCommand"
DockPanel.Dock="Right" Margin="0 5 5 0"
Width="30" HorizontalAlignment="Left"
Content="..." />
.....
But when i add this Usercontrol to a new Project like this:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:bibli="clr-namespace:EigeneControllsBibli;assembly=EigeneControllsBibli"
xmlns:uc="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1"
Title="Window1" Height="442" Width="804">
<Grid>
<uc:VideoPlayer Source="C:\Users\Public\Videos\Sample Videos\Bear.wmv" Margin="0,106,369,0"></uc:VideoPlayer>
</Grid>
i get an error that he cant convert the string in the Attribute "Command" into an Object of the Type "System.Windows.Input.ICommand
Does somebody see whats going wrong?
Thanks for helping,
Nico
you have a spelling-mistake:
LoadCommad = New RoutedUICommand("Load", "Load Video", GetType(VideoPlayer))
should be
LoadCommand = New RoutedUICommand("Load", "Load Video", GetType(VideoPlayer))
I don't know if this produces the error, but perhaps.
I think what you want to do is declare LoadCommand as an instance rather than Shared variable, so:
Public Class VideoPlayer
Inherits Control
...
Private ReadOnly m_LoadCommand As RoutedUICommand
....
Shared Sub New()
'This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
'This style is defined in Themes\Generic.xaml
DefaultStyleKeyProperty.OverrideMetadata(GetType(VideoPlayer), New FrameworkPropertyMetadata(GetType(VideoPlayer)))
End Sub
Sub New()
m_LoadCommand = New RoutedUICommand("Load", "Load Video", GetType(VideoPlayer))
End Sub
Public Property LoadCommand As ICommand
Get
Return m_LoadCommand
End Get
End Property
...
Then you bind the Button.Command property in the XAML, so:
<StackPanel>
<uc:VideoPlayer x:Name="myPlayer" Source="C:\Users\Public\Videos\Sample Videos\Bear.wmv" Margin="0,106,369,0"></uc:VideoPlayer>
<Button Command="{Binding ElementName=myPlayer, Path=LoadCommand"
Width="30"
Content="..." />
</StackPanel>

Resources