WPF - How to bind generic method in XAML? - wpf

I have a class with a static method that returns a Dictionary. The signature of the method is as follows:
public static Dictionary<int, string> CodeLookup<T>() where T : EntityCodeBase
At the moment, I'm using this method to bind to my comboboxes in the code behind, like so:
this.cboState.ItemsSource = CodeCache.CodeLookup<StateCode>();
Would someone please be able to point me in the correct direction for doing this in XAML so that I can remove this kind of stuff from my codebehind?
Thanks,
Sonny

Not directly binding to a particular method. You should create a property and bound that to it.
public Dictionary<int, string> Code {
get { return CodeCache.CodeLookup<StateCode>(); }
}

looks like you cannot do it for generic methods
more info

Here is a property in my viewModel:
public ObservableCollection<Contact> AllContacts
{
get { return _applicationViewModel.CurrentContacts; }
}
And here is my XAML:
<ListView Margin="5" ItemsSource="{Binding Path=AllContacts}">
<ListView.View>
<GridView>
<GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding Path=LastName}" />
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding Path=FirstName}" />
<GridViewColumn Header="Work Phone" DisplayMemberBinding="{Binding Path=OfficePhone, Converter={StaticResource phoneConverter}}" />
<GridViewColumn Header="Cell Phone" DisplayMemberBinding="{Binding Path=CellPhone, Converter={StaticResource phoneConverter}}" />
<GridViewColumn Header="Email Address" DisplayMemberBinding="{Binding Path=PrimaryEmail}" />
</GridView>
</ListView.View>
</ListView>
Just set the DataContext to the ViewModel and you get everything you need. Check out MVVM pattern for more info.
There are ways to bind to a static method but if all you are doing is basic databinding then it's a bit of overkill. Take a look at Actions if you are interested.

Related

Trying to do same thing with Listview/Gridview as I'm doing with DataGrid

guys!
I currently have this WPF Project With WCF and LINQ :
MainWindow.xaml
<GroupBox Header="Available Rooms" >
<DataGrid Name="roomDataGrid" ItemsSource="{Binding Rooms}" AutoGenerateColumns ="False" ">
<DataGrid.Columns>
<DataGridTextColumn Header="Room" Binding="{Binding RoomId}" />
<DataGridTextColumn Header="Reserved" Binding="{Binding RoomTaken}" />
<DataGridTextColumn Header="Beds" Binding="{Binding Beds}" />
<DataGridTextColumn Header="Size" Binding="{Binding Size}" />
<DataGridTextColumn Header="Rank" Binding="{Binding RoomRank}" />
</DataGrid.Columns>
</DataGrid>
</GroupBox>
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
viewModel = new ViewModel();
this.DataContext = viewModel;
}
ViewModel.cs
public class ViewModel
{
HotelService.HotelServiceClient hotelServiceClient = new HotelService.HotelServiceClient();
public List<RoomModel> Rooms
{
get
{
return hotelServiceClient.GetRooms().ToList();
}
}
}
So as you guys can see, I just set this.DataContext = viewModel and almost through sheer Magic, the WPF shows the database list of Rooms.
But my question is as following. Is there anyway I can achieve the same thing using a GridView/Listview ? I tried replacing the xaml with those Objects, but then it didn't show anything in the window.
Bonus question : Is there anyway to use GridView/ListView in accordance with events/delegates, so that I can save Rooms to DB and get the view updated, and also get the view updated when there are changes done to the DB that are not caused by this WPF?
I hope I supplied enough information! And thanks in advance :)
Try this:
<GroupBox Header="Available Rooms" >
<ListView Name="roomDataGrid" ItemsSource="{Binding Rooms}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Room" DisplayMemberBinding="{Binding RoomId}" />
<GridViewColumn Header="Reserved" DisplayMemberBinding="{Binding RoomTaken}" />
<GridViewColumn Header="Beds" DisplayMemberBinding="{Binding Beds}" />
<GridViewColumn Header="Size" DisplayMemberBinding="{Binding Size}" />
<GridViewColumn Header="Rank" DisplayMemberBinding="{Binding RoomRank}" />
</GridView>
</ListView.View>
</ListView>

WPF ListView Key Search Issue

I am using MVVM to show a list data in ListView. The ListView is very simple as follow:
<ListView HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Customers}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding FirstName}">
<GridViewColumnHeader Width="100" Content="First Name" />
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding LastName}">
<GridViewColumnHeader Width="100" Content="Last Name" />
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I bind a list of customer objects into ListView and the issue comes when I highlight a item in the ListView and start typing T. The ListView will highlight the next item each time you type a T character.
By spending some time to find out the issue, I track down it is because that my customer object has namespace TestMVVMProject so I think the ToString() function for customer object is always return TestMVVMProject.Customer
Can anyone give me some idea how to stop this behaviour?
This is because by default the ListView implements text searching ability. You can stop this behavious byusing the IsTextSearchEnabled property on the list box. Try
<ListView HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Customers}"
IsTextSearchEnabled="False">
This should disable the text search when you do not want it.
Edit:
After some investigation I found next solution:
<ListView
TextSearch.TextPath="FirstName"
...>
Hope this will help.
Original answer:
Just override ToString() on View Model and you will get proper behavior.
public class Customer
{
public string Name { get; set; }
public override string ToString()
{
return this.Name;
}
}

Binding textbox in ListView's header datatemplate to a filter property

I am creating a customized listview header that has the header text but also has a textbox that you can enter to filter the content of that column. My code currently looks like this:
<UserControl.Resources>
<DataTemplate x:Key="myHeaderTemplate">
<StackPanel>
<TextBlock FontSize="14" Foreground="DarkBlue" Margin="20,4" Text="{Binding}" />
<TextBox Text="" Margin="4,2" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
which is the definition for the header datatemplate containing the texbox; and the listview
<ListView ItemsSource="{Binding Path=MyData}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="Last Name" HeaderTemplate="{StaticResource myHeaderTemplate}"
DisplayMemberBinding="{Binding Path=Something}" />
<GridViewColumn Header="First Name" HeaderTemplate="{StaticResource myHeaderTemplate}"
DisplayMemberBinding="{Binding Path=Something}" />
<GridViewColumn Header="Address" HeaderTemplate="{StaticResource myHeaderTemplate}"
DisplayMemberBinding="{Binding Path=Tube}" />
</GridView>
</ListView.View>
</ListView>
I want to be able to build up a filter statement that I can apply to the listview rows, but to do that I have to get the data from each filter textbox in the header template.
Can I somehow bind the textboxes in the headers to properties on my viewmodel? If not is there some other way to get the text?
Thanks for any help.
You should be able to bind the header to a property like this:
<GridViewColumn
Header="{Binding LastNameFilter, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"
HeaderTemplate="{StaticResource myHeaderTemplate}"
DisplayMemberBinding="{Binding Path=Something}" />
The RelativeSource is needed to get to the DataContext of the ListView - you could also give it a name and use ElementName instead.
Now you can make a HeaderFilter class:
public class HeaderFilter
{
public string Name { get; set; }
public string Filter { get; set; }
}
Obviously you would need to extend that class to hook into the event when Filter is changed to perform the filtering.
Put a property for each column header on the object which is the DataContext for your ListView (same object which provides MyData probably)
public class SomeClass
{
....
public HeaderFilter LastNameFilter { get; set; }
....
}

How to specify hard-coded data for a multi-column WPF ListView?

Hey,
I have a ListView with mutliple columns. I wish to attach hard-coded values using a xaml construct like ListViewItem but can not work out how to specifiy multiple columns of fixed data. For example, in the grid shown below I'd like to see two columns, 'Animal' and 'IQ', and pre-populate the data for both columns, but the code shown sets all columns to the same value.
<ListView>
<ListView.View>
<GridView>
<GridViewColumn Header="Animal" />
<GridViewColumn Header="IQ" />
</GridView>
</ListView.View>
<ListViewItem Content="Pig"/>
<ListViewItem Content="Dog"/>
</ListView>
BTW: This is for a simple, sample screen. As such, I do not really want to bind programatically to data.
Thanks in advance.
Dave.
Not sure how to accomplish this declaratively in XAML, but if you don't want to bind data to the control, you could add programatically the items on the code-behind.
this.AnimalsList.Items.Add(new ListViewItem { Content = "Pig" });
this.AnimalsList.Items.Add(new ListViewItem { Content = "Dog" });
Just in case someone is still looking for an answer; the first answer is incorrect and will still print the same value in each column, just like the XAML example. This will do the trick:
<ListView>
<ListView.View>
<GridView>
<GridViewColumn Header="Animal" DisplayMemberBinding="{Binding Animal}" />
<GridViewColumn Header="IQ" DisplayMemberBinding="{Binding IQ}" />
</GridView>
</ListView.View>
<ListViewItem>
<local:Animals Animal="Pig" IQ="70" />
<local:Animals Animal="Dog" IQ="60" />
<local:Animals Animal="Frog" IQ="30" />
</ListViewItem>
However you do need a class like this, I don't think it can be done with pure XAML:
public class Animals
{
public string Animal { get; set; }
public int IQ { get; set; }
}

GridViewColumn not subscribing to PropertyChanged event in a ListView

I have a ListView with a GridView that's bound to the properties of a class that implements INotifyPropertyChanged, like this:
<ListView Name="SubscriptionView" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" ItemsSource="{Binding Path=Subscriptions}">
<ListView.View>
<GridView>
<GridViewColumn Width="24" CellTemplate="{StaticResource IncludeSubscriptionTemplate}"/>
<GridViewColumn Width="150" DisplayMemberBinding="{Binding Path=Name}" Header="Subscription"/>
<GridViewColumn Width="75" DisplayMemberBinding="{Binding Path=RecordsWritten}" Header="Records"/>
<GridViewColumn Width="Auto" CellTemplate="{StaticResource FilenameTemplate}"/>
</GridView>
</ListView.View>
</ListView>
The class looks like this:
public class Subscription : INotifyPropertyChanged
{
public int RecordsWritten
{
get
{
return _records;
}
set
{
_records = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("RecordsWritten"));
}
}
private int _records;
...
}
So I fire up a BackgroundWorker and start writing records, updating the RecordsWritten property and expecting the value to change in the UI, but it doesn't. In fact, the value of PropertyChanged on the Subscription objects is null. This is a puzzler, because I thought WPF is supposed to subscribe to the PropertyChanged event of data objects that implement INotifyPropertyChanged. Am I doing something wrong here?
Figured out the problem. The "Subscriptions" list was coming from a LINQ query. When I added .ToList() to the end of that query, the UI started updating properly.

Resources