WPF listview display converter - wpf

I have a collection of objects that derive from a Person class and I want to bind this collection to the ItemsSource of a ListView.
I want to specify a string to display in the ListView Items. This string will be a composite of properties found on the derived classes.
I also want to bind the SelectedItem of the ListView to a property of type Person in my view model.
As far as I see it I need a string converter for my display string but I'm unsure how to bind to the items within the ItemsSource to generate the composite display string.
Can anyone give me a pointer?
Thanks.

You can either overwrite the ToString() method of your derived classes to return your composite display string, or you can create a Converter like you are suggesting and pass it the entire Item. The converter would then check that the item is of a specified type, and if so compose a string of whatever properties you want.

you dont need the StringConverter, you need DataTemplate
using DataTemplate, you can choose how you would like to display you data as an item in your listBox.

If you could consider your derived class a ViewModel then you could just add a property to that class and then display it in the ListView ItemTemplate. Or like Rachel suggested override your ToString Method and then in your display binding simply write "{Binding}" which will force WPF to call the ToString method
e.g.
public class DerivedPerson : Person
{
public string DisplayString
{
get
{
return string.Format("{0} {1}",FirstName,LastName);
}
}
}
And you xaml:
<ListView ItemsSource="{Binding PersonList}" SelectedItem="{Binding SelectedPerson}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding DisplayString}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Related

Switching view/view model based on a parameter

In a wpf application I've to show different filter user control based on a parameter passed to the main view model. Each filter's view model implements IReportFilter and the main view model has a property of type
IReportFilter Filters {get;set;}
How do I resolve the correct xaml view?
Thanks in advance
Assuming that you have a base class instead of IReportFilter,say ReportFilter.
Follow the below steps:
1. Define DataTemplate For Filter1VM & Filter2VM & set the usercontrols.
Note that I have naming conventions while defining the control & VMs.
<DataTemplate DataType={x:type viewModels:Filter1VM}>
<usercontrols:Filter1/>
</DataTemplate>
<DataTemplate DataType={x:type viewModels:Filter2VM}>
<usercontrols:Filter2/>
</DataTemplate>
2. You need to define a custom DataTemplateSelector.
class CustomDataTemplateSelector:DataTemplateSelector
{
public ovverride DataTemplate SelectTemplate(object item,....)
{
Type t=item.GetType();
string typename=t.Name;
string viewName=typeName.Replace("VM",String.Empty);
DataTemplate dt=App.Current.Resources[viewname] as DataTemplate;
return dt;
}
}
3.Define a property TemplateSelector in ReportFilter class & initialise it in constructor as:
TemplateSelector=new CustomDataTemplateSelector();
4. In your window's VM, create ReportFilter Filter property:
ReportFilter Filter {get;set;}
In your application Window,add ContentControl where you need to place the filterControl:
ContentControl Content="{Binding Filter}"
ContentTemplateSelector="{Binding Filter.TemplateSelector}"
In your window's view model, assing Filter as Filter1VM/Filter2VM based on the parameter passed.
Try the following
<ContentControl Content="{Binding SomeContent}"/>
Then in viewmodel create two controls for your needs and simply switch them based on your filter
UPDATE
If you don't want to create controls in ViewModel then you can do the following for example:
<Grid>
<Column / Rows Definitions>
<YourControl1 Grid.Row="X" Grid.Column="Y" IsVisible={Binding BoolFilter1, Converter={StaticResource Bool2Visibility}/>
<YourControl1 Grid.Row="X" Grid.Column="Y" IsVisible={Binding BoolFilter2, Converter={StaticResource Bool2Visibility}/>
....
</Grid>

ListBox with ItemsSource of List<Dictionary<string, object>>

I'm setting the ItemsSource of a ListBox to the values of a ValueSet instance. Here is ValueSet:
public class ValueSet
{
public string valuetype;
public List<Dictionary<string, object>> values;
public double count;
}
Of course, the ListBox displays each item as "(Collection)" (list box on the right):
Each Dictionary<string,object> element in values is expected to have a pair with a key of text. I'd like for the ListBox to display the value of this pair. Can this be done by setting the DisplayMemberPath of the ListBox? If so what should it be set to? If not, what's a good way to achieve this?
At the very least you should be able to bind using the indexer syntax for binding "[text]". Use the ItemTemplate of the ListBox:
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=[text]}" />
You could also instead try setting DisplayMemberPath="[text]", but I have no idea whether that would work.
Using DisplayMemberPath we can able to achieve this by setting the Binding as Value. Please follow the below code snippet.
DisplayMemberPath="Value"

ItemsControl with databound ItemsSource and two-way binding of elements (replacable items)

I have an ObservableCollection of objects (e.g. Persons with First/Last Name) which I would like to display in an ItemsControl. Each Item is displayed in a custom "editor" control, which allows editing of the object's properties.
This part is working fine and fairly standard.
<ItemsControl ItemsSource="{Binding Persons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<custom:PersonEditor Person="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
However, the custom editor control also has the ability to replace the entire object is has received (rather than just editing a person's name, replace it with a new person object).
What I am looking for is a way to push this change back into the ObservableCollection. As it is now, changing the Person object within the editor does not replace the item in the list, which would be the desired outcome.
Any help would be appreciated.
If you don't have access to the custom control itself what you could try would be using a setter on a property to clear the ObservableCollection and re-add the items instead of outright replacing it.
For example:
private ObservableCollection<MyModel> _dataSource;
public ObservableCollection<MyModel> DataSource
{
get
{
return _dataSource;
}
set
{
_dataSource.Clear();
foreach(var item in value)
{
_dataSource.Add(item);
}
}
}
This would prevent the item itself from getting replaced which causes issues with ItemSources since they apparently only bind to the items property once.

binding to observable collection silverlight 4, grid

Can I bind a simple 'grid' to an observable collection? So i have a grid with just one column and several rows. The rows get populated at runtime with some hyperlinks which can get deleted/added etc. I don't want to write functions to add/remove them from the grid everytime and would prefer to use an observable collection and let the grid update itself. Can a simple grid do that ? i tried but it didn't even compile.
Thanks
[EDIT] Solved. The marked answer is correct [/EDIT]
Other answers cover various bases but your specific requirement is filled by the ItemsControl. You would probably want to contain it in ScrollViewer just in case where you have more links than can be seen at one time. You would have markup something like this:-
<ScrollViewer>
<ItemsControl ItemsSource="{Binding MyObsCollectionOfUrlInfo">
<ItemsControl.ItemTemplate>
<DataTemplate>
<HyperLinkButton NavigateUri={Binding Uri} Content={Binding Title} />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Your observable collection would contain a list of objects of a type like:-
public class UrlInfo
{
public Uri Uri {get; set; }
public string Title {get; set; }
}
Silverlight does not support this. You have two options, either use a DataGrid or use the following code that allows you to use a Grid within an ItemsControl which will achieve what you are after.
http://www.scottlogic.co.uk/blog/colin/2010/11/using-a-grid-as-the-panel-for-an-itemscontrol/
#ColinE is correct, you can't bind to a Grid, but you can bind an ObservableCollection to a DataGrid or an ItemsControl.

How do I bind the SelectedValue of a ComboBox to a Property?

I've got a ComboBox with an ItemsSource which I've bound to a List(Of String).
What I'd like to do is have the XAML update a String property when the SelectedValue of the ComboBox changes. I've seen a whole bunch of examples for TextBoxes which use
Text="{Binding Path=MyString}"
sort of stuff, but I don't really think that'll be the way to go if, in future, I need to change the ItemsSource to a List(Of ObscureObject)...
Binding to the selected property of a combobox is fairly simple.
XAML :
<ComboBox ItemsSource={Binding Path=MyCollection} SelectedItem={Binding Path=MyItem}/>
CodeBehind :
public List<string> MyCollection {get; set;}
public string MyItem {get; set;}
If you want to insert text into the selected item, you'll need to use INotifyPropertyChanged
as for your scalability issue, its a fairly minor change to update the type of a property to reflect a collection. Otherwise you could try binding to an Object although that would mean you would constantly have to recast the object back to the state you want.
You can use SelectedItem property of ComboBox to achieve this.
<ComboBox ItemsSource="{Binding Path=YouList}"
SelectedItem="{Binding Path=MyString}" />
When you change your list in future you will have to bind the SelectedItem with a property of your objects type.
Have a look at this article for more details -
http://japikse.blogspot.com/2008/10/wpf-combobox-selecteditem-selectedvalue.html

Resources