Autosizing templated column in a ListView based Multicolumn treeview - wpf

I'm using the multicolumn treeview control which I found here http://www.codeproject.com/KB/WPF/wpf_treelistview_control.aspx
The first column in this control which consists of a simulated tree view control needs to be autosized when a node is expanded/collapsed.
Any help?
Sample XAML
<UserControl x:Class="ListViewAsTreeView.XmlTree"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ListViewAsTreeView"
xmlns:tree="clr-namespace:Aga.Controls.Tree;assembly=Aga.Controls">
<UserControl.Resources>
<local:RegImageConverter x:Key="RegImageConverter"/>
<local:ComboList x:Key="MyComboSource"/>
</UserControl.Resources>
<StackPanel>
<tree:TreeList Name="_tree" local:DragAndDrop.DropEnabled="true"
MinHeight="40"
IsSynchronizedWithCurrentItem="True">
<tree:TreeList.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel
Orientation="Horizontal">
<tree:RowExpander/>
<Image
Source="{Binding
Converter={StaticResource RegImageConverter}}" Margin="0, 0, 5, 0"/>
<TextBlock
Text="{Binding Name}">
</TextBlock>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Type" Width="Auto"
DisplayMemberBinding="{Binding Kind, UpdateSourceTrigger=PropertyChanged}"/>
<GridViewColumn Header="Data" Width="Auto"
DisplayMemberBinding="{Binding Data, UpdateSourceTrigger=PropertyChanged}"/>
<GridViewColumn Header="ComboSample" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox Name="MyComboBox" ItemsSource="{StaticResource MyComboSource}"
IsEditable="True" IsEnabled="True"
Text="{Binding Name}">
</ComboBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</tree:TreeList.View>
</tree:TreeList>
<ListBox local:DragAndDrop.DragEnabled="true">
<ListBoxItem>Item 1</ListBoxItem>
<ListBoxItem>Item 2</ListBoxItem>
<ListBoxItem>Item 3</ListBoxItem>
</ListBox>
</StackPanel>
Thanks,
Jithu

Try defining a separate DataGrid and and populate with an item that contains longest column values. Then DataBind the Aga.Controls Treeview's column width to the corresponding column width of your DataGrid. That way TreeView control's column width is set to the longest column item. You can always hide the DataGrid by setting the opacity to zero.
e.g: Assume the DataGrid name is "TestDataGrid" and it has a column called "dgNameColumn"
<GridViewColumn Header="Name" **Width="{Binding ElementName=dgNameColumn, Path=ActualWidth}"**>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel
Orientation="Horizontal">
<tree:RowExpander/>
<Image
Source="{Binding
Converter={StaticResource RegImageConverter}}" Margin="0, 0, 5, 0"/>
<TextBlock
Text="{Binding Name}">
</TextBlock>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Hope this helps.

Output :
Parent Col1 Col2 Col3
|
|____ Child Data1 Data2 Data3
|
|____ Child2 Data1 Data2 Data3
http://www.go-mono.com/mono-downloads/download.html .. Download Gtksharp for ur operating system and add refrence of these dll in visual studio atk-sharp.dll , gdk-sharp.dll , glib-sharp.dll , gtk-sharp.dll and use using Gtk; ... U will get the TreeView
public class TreeViewExample
{
public static void Main()
{
Gtk.Application.Init();
new TreeViewExample();
Gtk.Application.Run();
}
public TreeViewExample()
{
Gtk.Window window = new Gtk.Window("TreeView Example");
window.SetSizeRequest(500, 200);
Gtk.TreeView tree = new Gtk.TreeView();
window.Add(tree);
Gtk.TreeViewColumn Parent = new Gtk.TreeViewColumn();
Parent.Title = "Parent";
Gtk.CellRendererText Parent1 = new Gtk.CellRendererText();
Parent.PackStart(Parent1, true);
Gtk.TreeViewColumn ChildColoumn1 = new Gtk.TreeViewColumn();
ChildColoumn1.Title = "Column 1";
Gtk.CellRendererText Child1 = new Gtk.CellRendererText();
ChildColoumn1.PackStart(Child1, true);
Gtk.TreeViewColumn ChildColumn2 = new Gtk.TreeViewColumn();
ChildColumn2.Title = "Column 2";
Gtk.CellRendererText Child2 = new Gtk.CellRendererText();
ChildColumn2.PackStart(Child2, true);
tree.AppendColumn(Parent);
tree.AppendColumn(ChildColoumn1);
tree.AppendColumn(ChildColumn2);
Parent.AddAttribute(Parent1, "text", 0);
ChildColoumn1.AddAttribute(Child1, "text", 1);
ChildColumn2.AddAttribute(Child2, "text", 2);
Gtk.TreeStore Tree = new Gtk.TreeStore(typeof(string), typeof(string), typeof(string));
Gtk.TreeIter iter = Tree.AppendValues("Parent1");
Tree.AppendValues(iter, "Child1", "Node 1");
iter = Tree.AppendValues("Parent2");
Tree.AppendValues(iter, "Child1", "Node 1","Node 2");
tree.Model = Tree;
window.ShowAll();
}
}

Related

WPF - Different SelectedValues in different GridViewColumns?

I have 12 Properties and I want to bind each of them to one GridViewColumn in a ListView. They contain an ID (string) and look like the following:
//DAR01
public static readonly PropertyInfo<string> DAR01Property = RegisterProperty<string>(p => p.DAR01);
/// <summary>
///Date type
/// </summary>
public string DAR01
{
get { return GetProperty( DAR01Property); }
set { SetProperty(DAR01Property, value); }
}
I also have a Key-Table in my database which contains a key and a description, which I already have in my Code-Behind:
public System.Collections.Generic.IEnumerable<AOK.NW.Beihilfe.Customizing.Schluessel> PlanungsdatenSchluessel
{
get
{
System.Collections.Generic.IEnumerable<AOK.NW.Beihilfe.Customizing.Schluessel> SchluessellistePlanungsdaten = Schluesselliste.GetSchluesselliste().Where<Schluessel>(x => x.Gruppe == "T548T");
return SchluessellistePlanungsdaten;
}
}
Basically the easiest way to explain what I want are these following ComboBoxes, but in a GridView with multiple GridViewColumns which have different Bindings:
<ComboBox Grid.Row="2" Grid.Column="1" Width="Auto"
ItemsSource="{Binding Path=PlanungsdatenSchluessel}"
DisplayMemberPath="Beschreibung"
SelectedValuePath="Id"
SelectedValue="{Binding Path=CurrentDate.DAR01}"
IsEnabled="{Binding Path=IsBearbeiten}"/>
<ComboBox Grid.Row="3" Grid.Column="1" Width="Auto"
ItemsSource="{Binding Path=PlanungsdatenSchluessel}"
DisplayMemberPath="Beschreibung"
SelectedValuePath="Id"
SelectedValue="{Binding Path=CurrentDate.DAR02}"
IsEnabled="{Binding Path=IsBearbeiten}"/>
[...]
My GridViewColumns (goes up to DAR12):
<ListView Grid.Row="0"
ItemsSource="{Binding Path=Person.Planungsdaten}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedItem}"
MaxHeight="580" Height="Auto"
Width="Auto"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Path=DAR01}">
<GridViewColumnHeader Name="DAR01" Content="Datentyp 01"/>
</GridViewColumn>
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Path=DAR02}">
<GridViewColumnHeader Name="DAR02" Content="Datentyp 02"/>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Any ideas how I can achieve that? I am grateful for any tip!

how to get column from listview in WPF

If we are using the DataGrid to get the value from the column I can use
var a = datagrid1.Columns[1].GetCellContent(item)
Can anyone please tell me how can I get the same value when using ListView instead of DataGrid. This ListView contains a GridView.
Try this
xaml
<ListView Margin="10" Name="UsersList" SelectionChanged="UsersList_SelectionChanged_1">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="colGrid">
<TextBlock Text="{Binding Name}" x:Name="txtBlock"/>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Age" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="colGrid">
<TextBlock Text="{Binding Age}" x:Name="txtBlock"/>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Mail" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="colGrid">
<TextBlock Text="{Binding Mail}" x:Name="txtBlock"/>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
SelectionChanged Event Handler of List View
private void UsersList_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
var gridView = UsersList.View as GridView;
ListBoxItem myListBoxItem =UsersList.ItemContainerGenerator.ContainerFromItem(UsersList.SelectedItem) as ListBoxItem;
//ContentControl does not directly host the elements provided by the expanded DataTemplate.
//It uses a ContentPresenter to do the work.
//If we want to use the FindName method we will have to pass that ContentPresenter as the second argument, instead of the ContentControl.
ContentPresenter myContentPresenter = myListBoxItem.GetVisualChild<ContentPresenter>();
foreach (var column in gridView.Columns)
{
//Here using FindName we can get the controls of cell template
var grid = column.CellTemplate.FindName("colGrid", myContentPresenter);
}
}
Visual Helper
public static class VisualHelper
{
public static T GetVisualChild<T>(this Visual parent) where T : Visual
{
T child = default(T);
for (int index = 0; index < VisualTreeHelper.GetChildrenCount(parent); index++)
{
Visual visualChild = (Visual)VisualTreeHelper.GetChild(parent, index);
child = visualChild as T;
if (child == null)
child = GetVisualChild<T>(visualChild);//Find Recursively
else
return child;
}
return child;
}
}
I hope this will help.

How to open the combobox in datagrid

I am very new to to silverlight application.I have been trying this for last one day still I am not able to do it. In my case it requires three clicks to open the combobox.
My XAML code:
<sdk:DataGridTemplateColumn Header="Category" Width="100">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Name="cmbCategory"
IsDropDownOpen="True"
ItemsSource="{Binding Source={StaticResource MyViewModel},Mode=OneWay,Path=pcProjTypeTaskCtry}"
DisplayMemberPath="TaskCtgyName" SelectedValuePath="TaskCtgy_FK"
SelectedValue="{Binding piTaskCtgy_FKField,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" ToolTipService.ToolTip="{Binding psTaskCtgyNameField,UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="SubCategory" Width="110">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Name="tbSubCategory" Text="{Binding Path=psTaskSubCtgyNameField,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" ToolTipService.ToolTip="{Binding psTaskSubCtgyNameField}" >
</TextBlock>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource MyViewModel},Mode=TwoWay,Path=pcTaskSubCtry}"
DisplayMemberPath="TaskSubCtgyName" SelectedValuePath="TaskSubCtgyName"
SelectedItem="{Binding Source={StaticResource MyViewModel},Path=SelectedSubTask,Mode=TwoWay}"
SelectedValue="{Binding psTaskSubCtgyNameField,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
ToolTipService.ToolTip="{Binding psTaskSubCtgyNameField}">
</ComboBox>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
Add a Dropdownopened event to the combobox and then assign the datasource to the combobox in the backend.
var obj = (ComboBox)sender;
obj.ItemsSource = Your list;
obj.DisplayMemberPath = "pcTaskSubCtry";
in the selection changed event you can assign the selected item by casting the selected item as below.
ComboBox cmbbox = (ComboBox)sender;
if (cmbbox.SelectedValue != null)
{
Yourobject obj = new Yourobject() ;
obj = MainDataGrid.SelectedItem as Yourobje;
obj.pcTaskSubCtry= Yourobje.pcTaskSubCtry;
}

WPF - How to center column data in ListView?

I'm still learning WPF, but I'm really confused about something that should be really simple. What I want to do is to center the contents of the 3rd and 4th columns. When I run this, the columns are left justified:
<ListView Margin="0" x:Name="listMonitoredUrls" AlternationCount="1"
ItemsSource="{Binding}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Description" DisplayMemberBinding="{Binding FriendlyDesc}"/>
<GridViewColumn Header="Url" DisplayMemberBinding="{Binding Url}"/>
<GridViewColumn Header="Frequency">
<GridViewColumn.CellTemplate >
<DataTemplate>
<TextBlock Text="{Binding ScanFrequencyMinutes}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Next Scan" >
<GridViewColumn.CellTemplate >
<DataTemplate>
<TextBlock Text="{Binding TimeNextScanStr}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I"m really starting to like WPF, but some simple things like this seem to be really hard.
Try using the TextAlignment property instead of HorizontalAlignment - should do it.
To my understanding HorizontalAlignment="Center" will center your textblock not the text in it.
This might be a long shot but i've had to do it for listboxes where the items are defined by templates. Try setting the HorizontalContentAlignment="Stretch" on your ListView. If I don't set that the items take only as much space as they need and are left justified.
I've created a solution which works under the common scenario of:
<GridViewColumn Header="Some Property" DisplayMemberBinding="{Binding SomeProperty}" />
where one only wants a simple DisplayMemberBinding with text without having to specify a CellTemplate
the new code uses an attached property and becomes:
<GridViewColumn Header="Some Property" DisplayMemberBinding="{Binding SomeProperty}"
ctrl:GridViewExtensions.IsContentCentered="True" />
attached property code:
public static class GridViewExtensions
{
#region IsContentCentered
[Category("Common")]
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static bool GetIsContentCentered(GridViewColumn gridViewColumn)
{
return (bool)gridViewColumn.GetValue(IsContentCenteredProperty);
}
public static void SetIsContentCentered(GridViewColumn gridViewColumn, bool value)
{
gridViewColumn.SetValue(IsContentCenteredProperty, value);
}
public static readonly DependencyProperty IsContentCenteredProperty =
DependencyProperty.RegisterAttached(
"IsContentCentered",
typeof(bool), // type
typeof(GridViewExtensions), // containing type
new PropertyMetadata(default(bool), OnIsContentCenteredChanged)
);
private static void OnIsContentCenteredChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
OnIsContentCenteredChanged((GridViewColumn)d, (bool)e.NewValue);
}
private static void OnIsContentCenteredChanged(GridViewColumn gridViewColumn, bool isContentCentered)
{
if (isContentCentered == false) { return; }
// must wait a bit otherwise GridViewColumn.DisplayMemberBinding will not yet be initialized,
new DispatcherTimer(TimeSpan.FromMilliseconds(100), DispatcherPriority.Normal, OnColumnLoaded, gridViewColumn.Dispatcher)
{
Tag = gridViewColumn
}.Start();
}
static void OnColumnLoaded(object sender, EventArgs e)
{
var timer = (DispatcherTimer)sender;
timer.Stop();
var gridViewColumn = (GridViewColumn)timer.Tag;
if (gridViewColumn.DisplayMemberBinding == null)
{
throw new Exception("Only allowed with DisplayMemberBinding.");
}
var textBlockFactory = new FrameworkElementFactory(typeof(TextBlock));
textBlockFactory.SetBinding(TextBlock.TextProperty, gridViewColumn.DisplayMemberBinding);
textBlockFactory.SetValue(TextBlock.TextAlignmentProperty, TextAlignment.Center);
var cellTemplate = new DataTemplate { VisualTree = textBlockFactory };
gridViewColumn.DisplayMemberBinding = null; // must null, otherwise CellTemplate won't be recognized
gridViewColumn.CellTemplate = cellTemplate;
}
#endregion IsContentCentered
}
Here is my example to show a working xaml:
<Window x:Class="WPF_Tutorial.Rich_text_controls.BlockUIContainerCenteredColumnSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:self="clr-namespace:WPF_Tutorial.Rich_text_controls"
Title="BlockUIContainerCenteredColumnSample" Height="275" Width="300"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<x:Array x:Key="UserArray" Type="{x:Type self:User}">
<self:User Name="John Doe" Age="42" />
<self:User Name="Jane May-Anne Josephine Renalds Doe" Age="36" />
</x:Array>
</Window.Resources>
<Grid>
<FlowDocumentScrollViewer>
<FlowDocument>
<Paragraph FontSize="36" Margin="0">Users</Paragraph>
<Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">Here's a list of our users, inside our FlowDocument, in a completely interactive ListView control!</Paragraph>
<BlockUIContainer>
<ListView BorderThickness="0" ItemsSource="{StaticResource UserArray}" HorizontalAlignment="Center">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<!-- This stretches out the TextBlock width to the column width -->
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="150" />
<GridViewColumn>
<GridViewColumnHeader Content="Age" Width="75" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Age}" TextAlignment="Center" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</BlockUIContainer>
<Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">More content can go here...</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
</Grid>
</Window>
Notice the <ListView.ItemContainerStyle> block. It has the <Setter ....
Without this, as per AndyG's text, nothing will work the way you want.
This has been very frustrating trying to work out.
By the way, here is the backing-code for this xaml:
namespace WPF_Tutorial.Rich_text_controls
{
using System.Windows;
public partial class BlockUIContainerCenteredColumnSample : Window
{
public BlockUIContainerCenteredColumnSample()
{
InitializeComponent();
}
}
public class User
{
public int Age { get; set; }
public string Name { get; set; }
}
}
What you should see when run

WPF: Progress bar in ListView

I'm trying to display information from my ObservableCollection<MyData> in a ListView. MyData has:
string Name
string Location
int Progress
Using DataBinding, I'm able to display the Name and Location for all the items in my ObservableCollection<MyData> in their own column. But how can I add a Progress column with a ProgressBar inside? Progress is a percentage.
<ListView ItemsSource="{Binding PersonList}">
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="GameName" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Width="140" Header="Progress">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ProgressBar Maximum="100" Value="{Binding Progress}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Your ListView in XAML:
<ListView x:Name="DataView">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Path=Name}" />
<ProgressBar Height="20" Width="100" Value="{Binding Path=Progress}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code-behind:
internal class MyData
{
public string Name { get; set; }
public int Progress { get; set; }
}
...
var items = new ObservableCollection<MyData>();
items.Add(new MyData() { Name = "Some", Progress = 25 });
items.Add(new MyData() { Name = "Another", Progress = 91 });
DataView.ItemsSource = items;
Just bind Progress property in MyData to the ProgressBar.Value and set the expected MAX value as the ProgressBar.Maximum for example 50 below
<ProgressBar Maximum="50" Value="{Binding Progress}" ..

Resources