Creating DataTemplate from code behind - c#

Sorry for the not so very general question...
I have a ListView that I have to fill from code behind, and this ListView also need to get its GridViewColumn's from code behind.
For strings it wasn't hard to make the connection, but now I wan't to create a Ellipse that represents a Boolean value in the ListView.
The code in XAML is rather easy, but I fail at converting it to c# code.
Here is parts of the XMAL code:
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
<DataTemplate x:Key="templateAdmin">
<DockPanel>
<Ellipse Width="8" Height="8" Visibility="{Binding Path=isAdmin, Converter={StaticResource BoolToVisibility}}" Fill="Black"/>
</DockPanel>
</DataTemplate>
</ResourceDictionary>
<ListView>
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding LastName}" Header="Last Name"/>
<GridViewColumn CellTemplate="{StaticResource templateAdmin}"
<GridViewColumnHeader">
<TextBlock Text="S"/>
</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
And by now I have gotten this far:
XAML:
<local:SortableListView >
<ListView.View>
<GridView x:Name="GroupListGridView" />
</ListView.View>
</local:SortableListView>
And in code I have a Collection<GridViewColumn> GridViewColumns that I loop throug and add all items to the GroupListGridView. And I have a function to fill the GridViewColumns collection:
private void CreateGridViews()
{
//Creating the Text was easy!
GridViewColumns.add(new GridViewColumn(){ Header = "LastName", DisplayMemberBinding = new Binding("LastName") });
//Creating the Ellipse was harder!
GridViewColumn gvc = new GridViewColumn();
DataTemplate dt = new DataTemplate();
gvc.DisplayMemberBinding = new Binding("isAdmin");
FrameworkElementFactory fef = new FrameworkElementFactory(typeof(Ellipse));
fef.SetValue(Ellipse.WidthProperty, 8.0D);
fef.SetValue(Ellipse.HeightProperty, 8.0D);
fef.SetValue(Ellipse.FillProperty, new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Black));
//I'm guessing that somewhere here there should be some binding to the visibility property and some sort of conversion done... But I can't figure out how!
dt.VisualTree = fef;
gvc.CellTemplate = dt;
GridViewColumns.Add(gvc);
}
I don't think that I'm that far of... Just that I can't figure out those last steps!

The missing lines are:
var ellipseVisBinding = new Binding("isAdmin");
ellipseVisBinding.Converter = new BooleanToVisibilityConverter();
fef.SetBinding(Ellipse.VisibilityProperty, ellipseVisBinding);
(I note that you've excluded the DockPanel in the template from your code version so I've removed that as well)

Related

How to resize ListView/GridView to contents in WPF

I would like to resize columns of a grid view into ListView to contents. There is the XAML code:
<ListView x:Name="listViewStatEntries"
AlternationCount="2" Grid.Row="8" Grid.ColumnSpan="3" Background="White"
ItemsSource="{Binding StatResult.StatEntries}" >
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Param.Speciality}">
<GridViewColumn.Header>
<GridViewColumnHeader Content="{Binding Labels[2851]}" Tag="Param.Speciality" Click="listViewStatEntriesColumnHeader_Click" Width="Auto" />
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Alarm}">
<GridViewColumn.Header>
<GridViewColumnHeader Content="{Binding Labels[2765]}" Tag="Alarm" Click="listViewStatEntriesColumnHeader_Click" Width="Auto" />
</GridViewColumn.Header>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I found this thread: Force resize of GridView columns inside ListView and try Oskar solution:
public void AutoSizeColumns()
{
GridView gv = listView1.View as GridView;
if (gv != null)
{
foreach (var c in gv.Columns)
{
// Code below was found in GridViewColumnHeader.OnGripperDoubleClicked() event handler (using Reflector)
// i.e. it is the same code that is executed when the gripper is double clicked
if (double.IsNaN(c.Width))
{
c.Width = c.ActualWidth;
}
c.Width = double.NaN;
}
}
}
But with this solution, columns was resized to visible contents only and not to all data into the ListView. How can I resize column to all data?
Thanks in advance for your help !
The reason they resize only to the visible rows is because you have virtualization on (which is default). Try turning it off
<ListView VirtualizingStackPanel.IsVirtualizing="False"

WPF - Filling a ListView

I have a 2 column ListView and I'm trying to fill it using and IDictionary with the following code.
System.Collections.IDictionary entryList = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User);
foreach (System.Collections.DictionaryEntry de in entryList)
{
Row row = new Row();
row.Name1 = (string)de.Key;
row.Name2 = (string)de.Value;
this.list1.Items.Add(row);
}
public class Row
{
public string Name1 { get; set; }
public string Name2 { get; set; }
}
XAML:
<ListView x:Name="varList"
Grid.ColumnSpan="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Height="400"
Width="500"
Margin="0, 30, 0, 0">
<ListView.View>
<GridView>
<GridViewColumn Width="150" Header="Name" />
<GridViewColumn Width="350" Header="Path" />
</GridView>
</ListView.View>
</ListView>
But every row and column gets filled with "Project.Views.Row".
Anyone got any idea on how to fix it? Thank you very much.
A ListView (and every other control for that matter) will display the results of calling ToString when given an object to display.
For a standard class, thats its qualified name; Project.Views.Row in your example.
There are two ways to fix this:
Don't add an object. Instead, format the string as you want it ie:
list1.Items.Add(String.Format({0}:{1}, row.Name1, row.Name2));
Do this the right way and use MVVM. In this case your XAML needs a data template:
<ListView ItemsSource="{Binding Rows}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name1}"/>
<TextBlock Text="{Binding Name2}"/>
</StackPanel>
</DataTemplate>
<ListView.ItemTemplate>
</ListView>
For a grid view:
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name1}" />
<GridViewColumn Header="Path" DisplayMemberBinding="{Binding Name2}"/>
</GridView>
</ListView.View>
Binding the ItemsSource is not actually necessary, but since we are doing everything the right way, you should do it so you are not directly manipulating the UI from code.

Listview binding doesn't update the view

I have this setup for my ListView and I am trying to make Binding to work in my MVVM structure.
This is the xaml code:
<Window.Resources>
<CollectionViewSource
x:Key="DeviceList"
Source="{Binding Path=DiscoveredDevicesList}">
</CollectionViewSource>
</Window.Resources>
<ListView
Grid.Row="1"
Width="500"
HorizontalAlignment="Left"
Margin="10"
Grid.Column="1"
DataContext="{StaticResource DeviceList}"
ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="Device name" DisplayMemberBinding="{Binding Path=DeviceName}"/>
<GridViewColumn Header="Rssi" DisplayMemberBinding="{Binding Path=Rssi}"/>
<GridViewColumn Header="GPS Row" DisplayMemberBinding="{Binding Path=GpsSignal}"/>
</GridView>
</ListView.View>
</ListView>
And the following is the code to implement the binding
//Constructor
public MainWindowViewModel()
{
DiscoveredDevicesList = new ObservableCollection<MyDeviceInfo>();
}
private ObservableCollection<MyDeviceInfo> _DiscoveredDevicesList;
public ObservableCollection<MyDeviceInfo> DiscoveredDevicesList
{
get
{
return _DiscoveredDevicesList;
}
set
{
_DiscoveredDevicesList = value;
OnPropertyChanged("DiscoveredDevicesList");
}
}
Using Add() and Clear() updates the view just fine when used as below:
var client = new BluetoothClient();
DiscoveredDevicesList.Clear();
IEnumerable<MyDeviceInfo> csaDevices = null;
csaDevices = await DiscoverCsaDevicesAsync(client);
foreach (var csaDevice in csaDevices)
{
DiscoveredDevicesList.Add(csaDevice);
DiscoveredDevicesList.First().GpsSignal = true;
}
So I can see the value of GpsSignal as changed to ture from initial opposite in my view.
However, if I put the following same line in the OnClick of a button doesn't do the same and the value stays false since I am not using any Add() or Clear() and I simply rely on the OnPropertyChanged to do the trick for me.
DiscoveredDevicesList.First().GpsSignal = true;
The rest of the bindings such as button clicks and textblock information work fine, then I would assume it shouldn't be the problem with implementation of the binding on the back of the stage.
Would appreciate your suggestions on this.
if your MyDeviceInfo class implement INotifyPropertyChanged and your property GpsSignal raise OnPropertyChanged() you should see all changes when your bindings are right.
nevertheless i would change your code in this way:
remove CollectionViewSource from your resources and use simple binding
<Window.Resources>
</Window.Resources>
<ListView ItemsSource="{Binding DeviceList}">
<ListView.View>
<GridView>
<GridViewColumn Header="Device name" DisplayMemberBinding="{Binding Path=DeviceName}"/>
<GridViewColumn Header="Rssi" DisplayMemberBinding="{Binding Path=Rssi}"/>
<GridViewColumn Header="GPS Row" DisplayMemberBinding="{Binding Path=GpsSignal}"/>
</GridView>
</ListView.View>
</ListView>
set the datacontext for your window to your MainWindowViewModel in codebehind or xaml.
instead of using OnClick, pls use ICommands (RelayCommand or DelegateCommand)
<Button Command="{Binding MyCommand4GpsSignalIsTrue}" />

How to increase the text size in a gridview

I am dynamically loading a xaml file. This is what the xaml looks like:
<ListView Grid.Row="2" BorderBrush="White"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="ListView1"
ItemsSource="{Binding Path=line}"
HorizontalAlignment="Stretch">
<ListView.View>
<GridView>
<GridViewColumn Header="Lines"
DisplayMemberBinding="{Binding Path=aline}" />
</GridView>
</ListView.View>
</ListView >
The xaml cannot be changed.
You can just change the FontSize in your xaml.
<ListView Grid.Row="2" BorderBrush="White" FontSize="20" .................
However if you are loading your Xaml from a file you will have to load it first then change the FontSize
Example:
using (FileStream stream = new FileStream("c:\\test.xaml", FileMode.Open))
{
var listView = (ListView)XamlReader.Load(stream);
// change font size
listView.FontSize = 20;
// apply listView to whatever you need
}

GridViewColumnHeader apply sorted style

I have the follwoing listview in my xaml:
<ListView Name="listView1">
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" Header="Name"
DisplayMemberBinding="{Binding nombre}" />
<GridViewColumn Width="200" Header="LastName"
DisplayMemberBinding="{Binding razonSocial}" />
// etc....
I have an ObservableCollection binded to a listview. I created the binding behind code. So any changes that I make to that collection will be reflected on the listview. Also if I want to sort the listview I will just sort the ObservableCollection.
I sort the listview when the user clicks on a gridviewcolumnheader as:
listView1.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler((a, b) =>
{
// check to see what column header was clicked
string bindingProperty =
((Binding)(((GridViewColumnHeader)(b.OriginalSource)).Column.DisplayMemberBinding)).Path.Path;
// using dyniamic linq libraries or the example located at
// http://stackoverflow.com/a/233505/637142
// I will be able to sort my collection of objects by nowing the property name
}));
Anyways I will like to apply a diferent style to the GridViewColumnHeader that was just clicked. I believe there should be already an existing template.
I am looking for something like:
GridViewColumnHeader a = "gridviewColumnHeader that was clicked"
a.Style = "orderByAscGridViewColumnTemplate"
Code Behind:
listView1.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler((a, e) =>
{
GridViewColumnHeader headerClicked =
e.OriginalSource as GridViewColumnHeader;
headerClicked.Column.HeaderTemplate =
Resources["HeaderTemplateArrowUp"] as DataTemplate;
xaml:
<UserControl.Resources>
<DataTemplate x:Key="HeaderTemplateArrowUp">
<DockPanel>
<TextBlock HorizontalAlignment="Center" Text="{Binding}"/>
<Path x:Name="arrow"
StrokeThickness = "1"
Fill = "gray"
Data = "M 5,10 L 15,10 L 10,5 L 5,10"/>
</DockPanel>
</DataTemplate>
</UserControl.Resources>

Categories