|
The awesome Karl Shifflett produced a great sample called BBQ Shack[^]. There is so much to learn in there.
|
|
|
|
|
|
Hello!
I'm testing WPF Toolkit DataGrid to display 2000-5000 rows.
I try to apply my control template for WPF Toolkit DataGrid.
VirtualizingStackPanel.IsVirtualizing set in True.
<Style x:Key="{x:Type DataGrid}" TargetType="{x:Type DataGrid}">
<Setter Property="MinRowHeight" Value="20"/>
<Setter Property="BorderThickness" Value="1" />
<Setter Property="SelectionUnit" Value="FullRow"/>
<Setter Property="IsReadOnly" Value="False"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="True"/>
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True"
Padding="{TemplateBinding Padding}">
<ScrollViewer Focusable="false" x:Name="DG_ScrollViewer">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Command="{x:Static DataGrid.SelectAllCommand}" Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=CellsPanelHorizontalOffset}" Focusable="false" Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.All}}" />
<DataGridColumnHeadersPresenter Grid.Column="1" Name="PART_ColumnHeadersPresenter" Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.Row="1" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" />
<ScrollBar Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" x:Name="PART_VerticalScrollBar"
Orientation="Vertical"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}">
</ScrollBar>
<Grid Grid.Row="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar Grid.Column="1"
Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsGrouping" Value="True">
<Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
</Trigger>
</Style.Triggers>
</Style>
But I need to set ItemsPresenter into some control(Border , Grid or Decorator etc.):
...
</ControlTemplate>
</ScrollViewer.Template>
<Border>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</ScrollViewer>
...
In this case, virtualization doesn't work, in spite of "VirtualizingStackPanel.IsVirtualizing = True".
Do you know some way that solve this problem?
Thanks.
|
|
|
|
|
Just as I suspected,
arno_cp wrote: <Style.Triggers> <Trigger Property="IsGrouping" Value="True"> <Setter Property="ScrollViewer.CanContentScroll" Value="False"/> </Trigger> </Style.Triggers>
You have to set the CanContentScroll to true if you want to use Virtualization .
You can also set the ItemsPanel of DataGrid to VirtualizingStackPanel .
People with high attitude deserve the standing ovation of our highest finger!
My Blog![ ^]
|
|
|
|
|
Good answer.
The funniest thing about this particular signature is that by the time you realise it doesn't say anything it's too late to stop reading it.
|
|
|
|
|
Thanks!
People with high attitude deserve the standing ovation of our highest finger!
My Blog![ ^]
|
|
|
|
|
Tarun.K.S wrote: You have to set the CanContentScroll to true if you want to use Virtualization .
You can also set the ItemsPanel of DataGrid to VirtualizingStackPanel .
I tried to set ItemsPresenter ScrollViewer.CanContentScroll = "True"... but there's no effect.
All properties used for virtualization are correct.
But if attach for application with Snoop, you can see all 2000 row controls.
DataGrid ItemsPanel is inheritor of VirtualizingStackPanel :
public class DataGridRowsPresenter : VirtualizingStackPanel
{
...
}
I think this is some limitation of wpf virtualization like grouping may be..
|
|
|
|
|
arno_cp wrote: I think this is some limitation of wpf virtualization like grouping may be..
Yes that's also true. Good that you pointed it out.
Here is an article by Bea Stollnitz : http://bea.stollnitz.com/blog/?p=338[^].
Check its Limitations section where she has described that :
When using data binding’s “Grouping” feature, there is no support for UI virtualization.
That explains why virtualization is not working.
People with high attitude deserve the standing ovation of our highest finger!
My Blog![ ^]
|
|
|
|
|
Hello there,
I was wondering if someone can get me started on how to represent a hierarchy in a TreeView that is derived from a MSSQL Server database with several levels of depth. For example:
- Department one
+ Group one
- Group two
+ Team one
- Team two
- Employee one
- Employee two
+ Team three
- Group three
- Team four
- Employee three
+ Department two
All departments are in a table tblDepartments
All groups are in a table tblGroups (with a foreign key linking to a DepartmentID)
All teams are in a table tblTeams (with a foreign key linking to a GroupID)
All employees are in a table tblEmployees (with a foreign key linking to a TeamID)
Ideally I would like to use a solution that uses WPF/LINQ if possible.
Many thanks,
Mark
|
|
|
|
|
Well, your TreeView representation should be based on the MVVM implementation described in this[^] excellent article. Basically I can see that you are going to need the following type of hierarchy:
public class DepartmentViewModel
{
public ObservableCollection<GroupViewModel> Groups { get; set; }
}
public class GroupViewModel
{
public ObservableCollection<TeamViewModel> Teams { get; set; }
}
public class TeamViewModel
{
public ObservableCollection<EmployeeViewModel> Employees { get; set; }
}
public class EmployeeViewModel
{
} Pay particular attention, in Josh's example, to the section on geographic breakdown with load on demand. That shows details about applying a complex hierarchy, and several excellent ideas for speeding up the loading of the tree by reducing the amount of data retrieved.
|
|
|
|
|
|
My pleasure. I'm glad to help.
|
|
|
|
|
Unfortunately, those two examples represent poor ways to implement treeviews in that they represent difficult ways to extend and enhance the data.
|
|
|
|
|
What does either answer even have to do with the OP's question? Not a dang thing .
|
|
|
|
|
I use a class called TreeNodeUI
public class TreeNodeUI
{
public TreeNodeUI(string sLabel,string sNodeKey,object oTag)
{
NodeLabel = sLabel;
NodeKey = sNodeKey;
NodeTag = oTag;
ChildNodes = new ObservableCollection<TreeNodeUI>();
}
public string NodeLabel { get; set; }
public string NodeKey { get; set; }
public object NodeTag { get; set; }
public ObservableCollection<TreeNodeUI> ChildNodes { get; set; }
}
and I load it with
public void LoadTree()
{
NodeList.Clear();
gUI.TreeNodeUI oNode;
FurnishCategoryList.OrderBy(x => x.Category);
foreach (FurnishCategoryDB oDB in FurnishCategoryList)
{
oNode= new gUI.TreeNodeUI(oDB.Category, string.Format("/{0}/", oDB.FurnishCategoryID), oDB);
LoadNode(oNode, oDB.FurnishCategoryID);
NodeList.Add(oNode);
}
}
private void LoadNode(gUI.TreeNodeUI oParent, int iCategoryID)
{
List<FurnishSubCategoryDB> lSC = VML.FurnishSubCategoryVMStatic.FurnishSubCategoryList.Where(x => x.CategoryID == iCategoryID).ToList();
oParent.ChildNodes.Clear();
foreach (FurnishSubCategoryDB oDB in lSC)
{
oParent.ChildNodes.Add(new gUI.TreeNodeUI(oDB.SubCategory, string.Format("/{0}/{1}/", oDB.CategoryID, oDB.SubCategoryID), oDB));
}
}
Note that I put the object into the NodeTag property for convenient retrieval.
Caveat I am bloody sure this is probably the most resource intensive method of managing a tree but it works!
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
Hi,
How is it possible to update a datagrid row?
While in the datagrid, I can change the value of one of the cells in a row but to update the data in the database, Is it that I first have to update the collection which is bound to the datagrid?
It seems that the datagrid in silverlight is quite different to that in asp.net because in asp.net, if I remember correctly, the datagrid has events for the edit, update, delete ?
Thanks
|
|
|
|
|
You can only update the database via a service.
You cannot directly update the service.
The funniest thing about this particular signature is that by the time you realise it doesn't say anything it's too late to stop reading it.
|
|
|
|
|
I am aware of the service but should the collection which populates the datagrid be updated first and then pass that to the service?
Thanks
|
|
|
|
|
That is sort of left to you.
You can update the collection or just send the "changed" values to the service (This way you can reduce network traffic).
Its basically left to how you implement this yourself.
The funniest thing about this particular signature is that by the time you realise it doesn't say anything it's too late to stop reading it.
|
|
|
|
|
Should the datagrid go into edit mode first to change the specific row in the datagrid?
|
|
|
|
|
Yes. This article[^] might help you (although its for SL2).
The funniest thing about this particular signature is that by the time you realise it doesn't say anything it's too late to stop reading it.
|
|
|
|
|
|
WPF binding is very different to (and much better than IMO) ASP.NET binding. WPF is unlike winforms or ASP.NET, so developers have to get their head around the change, which is substantial.
You bind an object exposing INotifyPropertyChanged a collection exposing IObservableCollection . If the binding is two-way, the object/collection is updated automatically. It is unlikely that this should be persisted immediately (in most circumstances the user would OK this somehow). Generally what would happen is the bound object would persist the changes. This is a better separation of concerns, and more flexible than binding an SQLDataSource to a grid as in ASP.NET.
This article explains a pattern that goes hand in hand with WPF: Model-View-ViewModel (MVVM) Explained[^] it should clarify things for you.
|
|
|
|
|
Hi,
Would you know how I do pass a command line with WPF (in VB.net)?
In WindowsForm I used
Shell("cmd.exe /c mame -listxml >xmlout.xml", 0, True)
(the app. Name and parameters, show/hide window, wait or not for the task being completed)
Unfortunately this line doens't work anymore in WPF
What should I use to send a command line with parameters?
Thanks very much for any kind help
modified on Tuesday, April 5, 2011 3:47 AM
|
|
|
|
|