|
I accidentally marked your post as trolling. Apologies for the error, your posts are constructive.
|
|
|
|
|
Don't worry about it. I have the feeling you're going to have to drop back to dotTrace to trace the performance of what's going on.
This space for rent
|
|
|
|
|
I get the impression you don't "understand" the purpose of these "configuration settings"; and because there are "a lot of them", a "grid" should do the trick.
Have you "talked" to the "engineers"?
WPF has the ability to "expand" "details" of a selected row.
One can have a list view of "grids"; etc.
What's missing is a UI "visual" designer; who's familiar with WPF (or not at all) ... oh, and familiar with the problem domain.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
Are you always so completely obnoxious?
You come across as a troll. Every single one of your posts is a put down. The suggestions you make are vague abstract comments (the kind that someone with no real knowledge could make), with no helpful content and nothing to indicate any actual technical knowledge on your part. Do you have anything constructive to say or is your goal simply to piss on me? Frankly I am getting pissed off with your obnoxious trolling.
The layout was designed by the engineers. It's what they have asked for and what they want. They've seen the current prototype and like it. It's the same as in the previous application which has served them well.
|
|
|
|
|
You talk in abstracts.
You're looking for advice, but won't accept any in terms of being more clear about the "use case".
Whatever the "layout" the engineers decided, it's only known to you apparently.
It's simple: you don't understand "virtualization" and refuse to.
(Later: I get it now why you were being so obtuse... it was because of the "NDA"; you should have made that clear from the beginning; then I wouldn't have bothered trying to help).
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
modified 25-Jun-18 11:56am.
|
|
|
|
|
Get lost.
|
|
|
|
|
NB: The solution is at the end.
We need to configure a hard ware device, which provides configuration settings as tabular data. There are lots of different sets of tabular data. We want to display a given table in a view, so that the user can edit the fields. All fields in a given row have the same kind of data e.g. integer. However, one row might display integers, another might display a combo box, and another a check box. The problem is how to automatically create the WPF view and view model code.
The nature of the data in each table is defined in an XML file. Unfortunately for one table the number of columns is defined by a value in another table which is only known at run-time.
Thus we can create some tables at build time, but one must be created at run-time.
I created a parser which generates the WPF view and view model for each table of data. This parser can be run at run-time to generate view and view model source code, which is then compiled at run-time, and displayed. So far so good. This works well with one exception, as the number of fields is almost always modest.
Unfortunately one table has ~120,000 cells, and the resulting view model will not run as the number of controls exceeds the maximum allowed by WPF. The view will display and looks good. Clearly having so many properties in a view model is a tad ridiculous and crude.
So, we need a more elegant solution, and one which allows the values to be displayed in a table with cells all nicely aligned.
The view model contains a list of field objects, each of which provides data in the correct format for the corresponding table cell e.g. "true" and "false" for tick box. Is it possible to create a DataGrid, such that it gets its data from my table of fields, and displays the correct kind of control dependent on the nature of the data (which my field object knows)? Thus row 0 might be tick boxes, row 1 edit boxes, and row 2 combo boxes?
==================================================================
Solution:
I came across some example code that almost solved our problem, and with some changes it does the job in my demo application which I will explain below in case anyone finds this useful. The link is as follows:
WPF DataGrid and binding to matrix of objects using UserControl per cell[^]
The first step is to declare some data templates in the XAML:
<DataTemplate x:Key="LabelDataTemplate">
<Label Margin="2" Content="{Binding Text}" Background="White"/>
</DataTemplate>
<DataTemplate x:Key="TextDataTemplate">
<TextBox Margin="2" Text="{Binding Text}" Foreground="Green" Height="20"/>
</DataTemplate>
<DataTemplate x:Key="ComboBoxDataTemplate">
<ComboBox Margin="2" Text="{Binding ComboText}" ItemsSource="{Binding Values}" Foreground="Red" Height="20" VerticalAlignment="Center"/>
</DataTemplate>
<DataTemplate x:Key="CheckBoxDataTemplate">
<CheckBox Margin="2" IsChecked="{Binding IsChecked}" Foreground="Red" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</DataTemplate>
The data grid is very basic:
<DataGrid Grid.Row="2" Name="_dataGrid2" ItemsSource="{Binding Matrix}" AlternationCount="2" AutoGenerateColumns="False" Style="{StaticResource styleDataGridNoSelection}" HeadersVisibility="None">
The style simply makes it look nice for our usage. The key point is the binding to Matrix, which is a matrix of nodes:
namespace WpfGridDemo.Model
{
public class Node
{
public NodeType Type { get; set; }
public string Text { get; set; }
public bool IsChecked { get; set; }
public string ComboText { get; set; }
public List<string> Values { get; set; }
}
}
The type indicates whether it is text, a combo box, a checkbox or a label. In real code this would be better as a polymorphic base class, but since this was a quick demo, the above is good enough.
A Row class wraps an array of nodes and represents a row from the matrix:
namespace WpfGridDemo
{
public class Row
{
private string name;
private Model.Node[] values;
public string Name { get { return name; } }
public Model.Node[] Values { get { return values; } }
public int Index { get; set; }
const int constColumnCount = 40;
}
}
And the Matrix is defined in the view model as an array of rows:
private Row[] _matrix;
public Row[] Matrix { get { return _matrix; } }
So it is just a 2D matrix of rows.
In the main window class I set up the binding between the matrix nodes and data grid:
public MainWindow()
{
InitializeComponent();
MainViewModel viewModel = new MainViewModel();
DataContext = viewModel;
for (int i = 0; i < 40; i++)
{
DataGridTemplateColumn col = new DataGridTemplateColumn();
FrameworkElementFactory fef = new FrameworkElementFactory(typeof(ContentPresenter));
Binding binding = new Binding();
fef.SetBinding(ContentPresenter.ContentProperty, binding);
GridDataTemplateSelector gridDataTemplateSelector = new GridDataTemplateSelector();
gridDataTemplateSelector.LabelDataTemplate = Resources["LabelDataTemplate"] as DataTemplate;
gridDataTemplateSelector.TextDataTemplate = Resources["TextDataTemplate"] as DataTemplate;
gridDataTemplateSelector.CheckBoxDataTemplate = Resources["CheckBoxDataTemplate"] as DataTemplate;
gridDataTemplateSelector.ComboBoxDataTemplate = Resources["ComboBoxDataTemplate"] as DataTemplate;
fef.SetValue(ContentPresenter.ContentTemplateSelectorProperty, gridDataTemplateSelector);
binding.Path = new PropertyPath("Values[" + i + "]");
DataTemplate dataTemplate = new DataTemplate();
dataTemplate.VisualTree = fef;
col.CellTemplate = dataTemplate;
_dataGrid2.Columns.Add(col);
}
}
A key point is the DataTemplateSelector which tells the grid which data template to use for a given cell.
class GridDataTemplateSelector : DataTemplateSelector
{
public DataTemplate LabelDataTemplate { get; set; }
public DataTemplate TextDataTemplate { get; set; }
public DataTemplate CheckBoxDataTemplate { get; set; }
public DataTemplate ComboBoxDataTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
Model.Node node = item as Model.Node;
if (node != null)
{
if (node.Type == Model.NodeType.Label)
{
return LabelDataTemplate;
}
if (node.Type == Model.NodeType.Text)
{
return TextDataTemplate;
}
if (node.Type == Model.NodeType.CheckBox)
{
return CheckBoxDataTemplate;
}
if (node.Type == Model.NodeType.ComboBox)
{
return ComboBoxDataTemplate;
}
}
return TextDataTemplate;
}
}
I'm quite certain I would not have solved this without the online code I found. Hopefully I can put this into a little demo project in a short article as I feel it is useful.
modified 8-Jun-18 3:33am.
|
|
|
|
|
Leif Simon Goodwin wrote: Unfortunately one table has ~120,000 cells, and the resulting view model will not run as the number of controls exceeds the maximum allowed by WPF Virtualization will be your friend here. You don't actually need to hold all those cells in memory - especially as you wouldn't be able to physically see them on the screen at the same time.
This space for rent
|
|
|
|
|
The fact it "looks" like a grid, doesn't mean you need to use a "DataGrid" control.
You haven't even established a "view port"; i.e. how many cells you expect to "see" at any one time.
Then you can start thinking in terms of "pages" (and virtualization; as has been already suggested).
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
Thanks. The number of cells visible is determined by the user and the monitor size, but roughly 30 by 30 say. However, it is a variable.
|
|
|
|
|
I'm using the WPF Toolkit PropertyGrid
I'd like to create a context menu on each property with Cut, Copy, Paste, Undo, and Reset. There doesn't seem to be any documentation at all, and I can't find any resources on this.
Has anyone done this that can help out?
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
There's some limited documentation on the Xceed site: PropertyGrid Class | Xceed Toolkit Plus for WPF v3.6 Documentation[^]
But it's not great, and it's mixed in with documentation for the commercial "plus" version.
I can't find anything about creating a custom context menu for a property.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I've already see it
That's not documentation. That's an API. An API tells you WHAT it does, not HOW to do it.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Agreed - their documentation is sorely lacking.
It might be worth posting this question in their support forum as well:
Xceed Toolkit Plus for WPF – Xceed[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I created an Image button called MultiImageButton with 4 properties for Normal, Mouse Over, Disabled, and Pressed. I won't post the class code (unless you want me to ) because it works and isn't the problem. The class is in the Controls folder.
In the same project I created a style for it:
<ResourceDictionary 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"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:cctrls="clr-namespace:Controls"
mc:Ignorable="d">
<pre>
<!THE TEMPLATE>
<ControlTemplate x:Key="MultiImageButtonTemplate"
TargetType="{x:Type cctrls:MultiImageButton}">
<Grid x:Name="Grid">
<Border x:Name="Background"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="0"
Visibility="{Binding BorderVisibility, RelativeSource={RelativeSource TemplatedParent}}"/>
<StackPanel Orientation="Horizontal"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
<Image x:Name="ButtonImage"
Source="{Binding NormalImage, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding ImageSize, RelativeSource={RelativeSource TemplatedParent}}"
Width="{Binding ImageSize, RelativeSource={RelativeSource TemplatedParent}}"
ToolTip="{TemplateBinding ToolTip}"/>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True" />
</StackPanel>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="ButtonImage" Property="Source" Value="{Binding HoverImage, RelativeSource={RelativeSource TemplatedParent}}" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="ButtonImage" Property="Source" Value="{Binding PressedImage, RelativeSource={RelativeSource TemplatedParent}}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="ButtonImage" Property="Source" Value="{Binding DisabledImage, RelativeSource={RelativeSource TemplatedParent}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!IMAGE BUTTON BASE STYLE>
<Style x:Key="MultiImageButtonStyle"
TargetType="{x:Type cctrls:MultiImageButton}"
BasedOn="{StaticResource {x:Type cctrls:MultiImageButton}}">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template" Value="{StaticResource MultiImageButtonTemplate}" />
</Style>
<!NAV LEFT BUTTON STYLE>
<Style x:Key="NavLeftButtonStyleStyle"
TargetType="{x:Type cctrls:MultiImageButton}"
BasedOn="{StaticResource MultiImageButtonStyle}">
<Setter Property="ImageSize" Value="32"/>
<Setter Property="NormalImage" Value="/GenMarkDX.RemoteManagement.Common;component/Media/Images/arrow_left_normal.png"/>
<Setter Property="HoverImage" Value="/GenMarkDX.RemoteManagement.Common;component/Media/Images/arrow_left_mouseover.png"/>
<Setter Property="PressedImage" Value="/GenMarkDX.RemoteManagement.Common;component/Media/Images/arrow_left_normal.png"/>
<Setter Property="DisabledImage" Value="/GenMarkDX.RemoteManagement.Common;component/Media/Images/arrow_left_disabled.png"/>
</Style>
In a different project I added it to a window:
xmlns:cctrls="clr-namespace:Common.Controls;assembly=Common"
.
.
.
<cctrls:MultiImageButton Grid.Row="1"
Grid.Column="0"
Command="{Binding NavLeftCommand}"
Margin="5"
Style="{StaticResource NavLeftButtonStyleStyle}"/>
When I run this I get the error: "Cannot find resource named 'Common.Controls.MultiImageButton'. Resource names are case sensitive."
Again, the class with the button is in the same project as the style. There's no reason that I can see why the style shouldn't find the class. This works in a different app, just not here.
Anyone see what's wrong?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
We declare our styles in the app.xaml as MergedDictionaries. It feels like you are just referencing the assembly CommonControls
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Assets/Styles/Brushes.xaml" />
They then become available as StaticResources, not sure if that helps or not.
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
I've got the following DataGridTemplateColumn with a UserControl as its DataTemplate. I can't get the binding right. I need it to bind to the grid's data. What am I doing wrong here?
<DataGrid.Columns>
<DataGridTemplateColumn Header="Value">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding PropertyType}" Value="{x:Static ca:PropertyType.Boolean}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ctrls:CheckBoxPropertyView IsCheckedValue="{Binding Value}"/> <==HERE
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Bindings for value DataGridTemplateColumns don't show correctly in the designer intellisense, though they are binding to the ItemSource for your grid. It's an annoyance that I've learned to live with, as the values do bind correctly at run time.
That said, your style trigger is pretty mungy. Is there a terribly compelling reason that you can't do:
<DataGrid.Columns>
<DataGridTemplateColumn Header="Value">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ctrls:CheckBoxPropertyView IsCheckedValue="{Binding Value}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
"There are three kinds of lies: lies, damned lies and statistics."
- Benjamin Disraeli
|
|
|
|
|
Nathan Minier wrote: Is there a terribly compelling reason that you can't do:
There can be any number of UserControls. Each row will have a different one based on the PropertyType enum set in the DataTrigger
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
That would be a compelling reason!
"There are three kinds of lies: lies, damned lies and statistics."
- Benjamin Disraeli
|
|
|
|
|
I have this DataGrid:
<DataGrid Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
ItemsSource="{Binding Files}"
SelectedItem="{Binding SelectedFile}">
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="Selected" Width="55" Binding="{Binding IsSelected, Mode=TwoWay}" IsReadOnly="{Binding IsFixed}" />
<DataGridTextColumn Header="File Name" Width="50*" Binding="{Binding FileName}"/>
</DataGrid.Columns>
</DataGrid>
The checkbox column is bound to a bool property on the FileEntity called IsSelected. When I click the checkbox inside the checkbox column the IsSelected property's Setter is not firing.
I also have a Select All button that calls this on the VM:
private void SelectAllExecuted()
{
foreach (var file in Files)
{
file.IsSelected = true;
}
}
This DOES cause the IsSelected's property to fire for each file entity.
Anyone see what's wrong?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Try setting the UpdateSourceTrigger :
<DataGridCheckBoxColumn Header="Selected" Width="55" Binding="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsFixed}" /> (As suggested in this SO post[^].)
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
That did it.
ya, Im an idiot.. never even thought to set it
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Can anyone share how to add a NIC receive bytes/s counter to a WPF form?
|
|
|
|
|
C# - Performance Counters
Read the counter; add the counter to a WPF window (as a TextBlock or whatever).
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|