Means of generating an editable form from XML - c#

<press_limits value="1055" label="Press Limits" type="single 317" format="object">
<projected_area value="0.052944637336319995" label="Projected area of part" type="real(m*m)"/>
<press_tonnage value="500.0" label="Press tonnage" type="real(g)" units="0Ton"/>
<within_press_limit value="1" label="within limits of press" type="boolean"/>
From XML like the above, the XAML below will generate a form that displays the values, with appropriate controls and value formats. But I can't get the stuff converted back. I fail to see a simple change that will meet the requirements of Binding. Perhaps fixing this requires an architecture change. How can I do this differently?
The magic starts here. Bind this ItemsControl to an XmlElement, and it builds a ControlChooser for each subelement.
<ItemsControl ItemsSource="{Binding XPath=*}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<W3V:ControlChooser Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The ControlChooser triggers on the format attribute:
<Style.Triggers>
<DataTrigger Binding="{Binding XPath=#format}" Value="spin">
<Setter Property="ContentTemplate" Value="{StaticResource combo}" />
</DataTrigger>
to pick a DataTemplate:
<DataTemplate x:Key="combo" > <W3V:ComboView /> </DataTemplate>
which instatiates the following control:
<ComboBox Style="{StaticResource ComboButtonStyle}" Width="200"
Text="{Binding Path=., ## PROBLEM, BUT HOW TO AVOID?
Converter={StaticResource valueFormattingConverter },
IsEditable="True" />
valueFormattingConverter uses the #units, #type, and #value attributes to produce properly formatted text. The trouble is, this doesn't convert back. I asked here: TextBox ConvertBack event doesn't fire for XML element, and learned that it is impossible for Path=. to be used as '.' is an object but not a dependency property.
So then, I need a way to provide a DependencyProperty for Binding. So ComboView needs to receive an object that has a property which is or has the XmlElement I want. I think this means I really need to change things around but haven't the slightest idea how. Maybe there's an MVVM approach to doing this??? Any insights will be appreciated.
An upcoming issue is a need to validate the data typed in and process the information.

The MVVM method: pull the data out of the XML file, and put it a class which is the ViewModel. Each property in the ViewModel corresponds to an item of data in the XML file. Then use a custom DataTemplate to render the contents of the ViewModel to the screen.
We can extend this to render a list of items. Each item in the list is a ViewModel. A DataTemplate always renders based on the type of the property it is attached to. So you can have a list of objects, and a custom DataTemplate for each item in the list. Of course, all of the items in the list would have to inherit from the same type.
This means you can have a list of items, and each item can render differently depending on the type of data in the XML file. This means that each item in the list can have a custom look and feel with different number of decimal places, colors, etc.
I've used this technique before, and it works well.
Update
For examples, see:
http://www.wpftutorial.net/datatemplates.html
http://www.stackoverflow.com/questions/3400532/display-multiple-types-from-a-single-list-in-a-wpf-listbox.

If I was solving this, I would look at generating C# on the fly. Here is how I would do it:
All XAML compiles to a series of C# commands.
I would set the XAML to format things the way I like it.
I would find the equivalent C# code.
I would then insert the appropriate if/else statements to alter the C# to suit.
Another method that I would try:
Its possible to render custom XAML into an area on the screen.
I would edit the XAML, based on the XML, then display this custom XAML on the screen.
I'd be curious to know if either of these methods work in practice, or if there is a better method that would work.

Related

WPF/ItemsControl How to Bind to Index of Another Collection Using AlternationIndex

Let me preface this by saying, I'm not sure if this is even possible. I've got two similar collections of complex objects that I'm using as source data for two different Items controls. Well, let's call the first collection the old data, and let's call the second collection the new data.
Like I said above, I've got two items controls - one binding to old, and the other binding to new. Well, in the item template of the new items control, I want to be able to bind to the old data, however I need to be able to use an index because the property is List of items. Maybe code snippets will help explain what I'm after:
<ItemsControl.ItemTemplate>
<DataTemplate>
<Textblock Text="{Binding Path=OldSourceData.MyList[0]}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
However, I need to replace 0 with the alternation index of the current item. I'm using this to get the correct index {Binding Path=(ItemsControl.AlternationIndex), RelativeSource={RelativeSource TemplatedParent}}
How do I replace 0 with the alternation index?
EDIT
I'm trying to figure out how to do something like this: <Textblock Text="{Binding Path=OldSourceData.MyList[{Binding Path=(ItemsControl.AlternationIndex), RelativeSource={RelativeSource TemplatedParent}}]}"/> Obviously, this syntax doesn't work, however is it possible to accomplish this somehow?

View / Edit dynamic parameters in a grid

I'm evaluating the possibilities to view and edit parameters in a C#/WPF/MVVM application. I'm currently looking into some custom controls from WPF Woolkit Extended, Telerik, DevExpress and Syncfusion. I see two options, a PropertyGrid or a DataGrid-like control.
The problem: My parameter content is in a collection and PropertyGrids don't seem to like those, they like to be bound to objects with properties. On the other hand my parameters have different value types and that is something the Data Grids do not favor, there the columns always have the same value editor (e.g. Check box, Date picker etc).
Does anybody know a reliable control that supports binding to a collection and individual value editors per row?
Other requirements are hierarchical data representation, validation and a search function.
DataGrid lets you use a DataGridTemplateColumn, where you can specify a template that will be applied to each cell in that column. This template could contain a UserControl that you have defined, which analyzes its DataContext and shows the appropriate control. (This will be quite a bit of work, though, so if there exist out-of-the-box solutions for this, you should use that instead.)
After a while of investigation I found out that all frameworks have the ability to apply individual cell editors in columns.
This is usually done in the column definition. A grid has a Columns collection. Each column can set a CellTemplateSelector which was the key to my initial problem.
Here is a little snippet for the Telerik grid view, but down to the CellTemplateSelector they all behave the same, as far as I can judge. All the vendor of 3rd party UI libs seems to have copied the behviour of the WPF DataGrid, of course.
<telerik:RadGridView x:Name="radGridView"
AutoGenerateColumns="False">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Name}" Header="Parameter" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding Value}" Header="Value">
<telerik:GridViewDataColumn.CellTemplateSelector>
<telerik:ConditionalDataTemplateSelector>
<telerik:DataTemplateRule Condition="PropertyId < 1">
<DataTemplate>
<TextBox Text="{Binding Value, StringFormat=c}"/>
</DataTemplate>
</telerik:DataTemplateRule>
<telerik:DataTemplateRule Condition="PropertyId > 0">
<DataTemplate>
<CheckBox IsChecked="{Binding Value}" />
</DataTemplate>
</telerik:DataTemplateRule>
</telerik:ConditionalDataTemplateSelector>
</telerik:GridViewDataColumn.CellTemplateSelector>
</telerik:GridViewDataColumn>
</telerik:RadGridView.Columns>
In this example the ItmesSource of the grid is bound to my view model that contains Name, Value and PropertyId properties. Based on the PropertyId a control is selected. The thing I like about the Telerik control is that I don't need code-behind since the ConditionalDataTemplateSelector is available in that framework. Better for MVVM to keep your view clean of code behind, I guess.
UPDATE:
Just received an answer from Syncfusion, they say:
We can load different cell editors in one column. For that we have to Handle dataGrid.Model.QueryCellInfo even and we have to change the CellType based on data. We can't avoid code behind. But this can be achieved using Behaviors.

WPF Binding to parent DataContext

We have a WPF application with a standard MVVM pattern, leveraging Cinch (and therefore MefedMVVM) for View -> ViewModel resolution. This works well, and I can bind the relevant controls to properties on the ViewModel.
Within a particular View, we have an Infragistics XamGrid. This grid is bound to an ObservableCollection on the ViewModel, and displays the appropriate rows. However, I then have a specific column on this grid which I am trying to bind a TextBox text value to a property on the parent DataContext, rather than the ObservableCollection. This binding is failing.
We've gone through several options here including:
Using AncestorType to track up the tree and bind to the DataContext of the parent UserControl like so (from the great answer to this question, as well as this one)...
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
Specifying the ElementName and trying to target the top level control directly. Have a look here if you'd like to read about using ElementName.
Using a 'proxy' FrameorkElement defined in the resources for the UserControl to try and 'pass in' the context as required. We define the element as below, then reference as a static resource...
<FrameworkElement x:Key="ProxyContext" DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}"></FrameworkElement>
In this case the binding finds the FrameworkElement, but can not access anything beyond that (when specifying a Path).
Having read around, it looks quite likely that this is caused by the Infragistics XamGrid building columns outside of the tree. However, even if this is the case, at least options 2 or 3 should work.
Our last thoughts are that it is related to the V - VM binding, but even using Snoop we've yet to find what the exact issue is. I'm by no means an expert with WPF binding so any pointers would be appreciated.
EDIT: I have found some templating examples from Infragistics here that I will try.
EDIT 2: As pointed out by #Dtex, templates are the way to go. Here is the relevant snippet for use with a XamGrid:
<ig:GroupColumn Key="CurrentDate">
<ig:GroupColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=DataContext.CurrentDateTest, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</DataTemplate>
</ig:GroupColumn.HeaderTemplate>
<ig:GroupColumn.Columns>
I've left the XML open... you'd simply add the columns you wanted, then close off the relevant tags.
I dont know about XamGrid but that's what i'll do with a standard wpf DataGrid:
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataContext.MyProperty, RelativeSource={RelativeSource AncestorType=MyUserControl}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding DataContext.MyProperty, RelativeSource={RelativeSource AncestorType=MyUserControl}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Since the TextBlock and the TextBox specified in the cell templates will be part of the visual tree, you can walk up and find whatever control you need.
Because of things like this, as a general rule of thumb, I try to avoid as much XAML "trickery" as possible and keep the XAML as dumb and simple as possible and do the rest in the ViewModel (or attached properties or IValueConverters etc. if really necessary).
If possible I would give the ViewModel of the current DataContext a reference (i.e. property) to the relevant parent ViewModel
public class ThisViewModel : ViewModelBase
{
TypeOfAncestorViewModel Parent { get; set; }
}
and bind against that directly instead.
<TextBox Text="{Binding Parent}" />

Can I implement ScrollToHorizontalOffset() functionality in XAML? (for a dynamic list)

Here's the problem: I have a data-bound list of items, basically a way for users to map a request to a response. The response is an xml-based file. I'm letting them queue these up, so I've used a combobox for responses. The responses will include the full path, so they get a bit long. I want the displayed text of the combobox to be right-justified so the user can see the file name. For my static controls, I just use ScrollToHorizontalOffset() when a file is loaded and I'm done. For this dynamic list, I'd like to do it in xaml.
The "somewhat ugly" solution would be to store all the ComboBox objects as they load... then I can call ScrollToHorizontalOffset() directly, but I'd really prefer to do it a cleaner way than that! EDIT: (Actually, this may not be reasonable. A quick look at trying to hack around this issue gets into some really awkward situations trying to map my datasource items to the controls)
I've tried HorizontalContentAlignment, that only impacts the "dropped-down" portion of the ComboBox.
I've also tried to hook other various loading events, but haven't found one that works.
Using an Item template you can decide what will be shown.
You can set tooltip. You can then also use converters to add the dots.
<ComboBox x:Name="ConfigurationComboBox" VerticalContentAlignment="Center" ToolTip="saved configuration" SelectionChanged="ConfigurationComboBox_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate >
<StackPanel>
<TextBlock Text="{Binding}" ToolTip="{Binding Path}"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
To measure the text, see Measuring text in WPF.

C# 'if' Binding value

I've got a list view that is populated by a Binding, on a class named House.
Here's an example of my code:
<DataTemplate DataType="house">
<TextBlock Text="{Binding sold_status}" />
</DataTemplate>
As you can see, one of my variable names is sold_status. This is a bool.
I want to show either "SOLD" or "NOT SOLD" for 1 and 0 respectively.
Is it possible to fashion an if statement based on the value?
So just so that you can visualise what I want to achieve:
<DataTemplate DataType="house">
<TextBlock Text="({Binding sold_status} == 1) 'SOLD' else 'NOT SOLD'" />
</DataTemplate>
You'll want to create a Style with DataTriggers in to set the properties as needed. You could also use a converter, but changing UI control properties based on underlying data is exactly what triggers/styles are all about.
..In fact, I can see you're basically 'converting' sold_status to a bit of text. For that, use a converter. I'll post a quick example..
See the top answer here: WPF: Display a bool value as "Yes" / "No" - it has an example converter class you could repurpose.
Look up the IValueConverter interface for an example. Implement the Convert method to return the text you want to display.
You want to use a value converter.
A better approach to this would be to use a converter. Keep the binding as you have done in your first example then have the converter return a string with "Sold" if true etc.
I suggest you to use a DataTrigger. It's quite simple and doesn't require separate converter.
<DataTemplate DataType="house">
<TextBlock x:Name="Status" Text="SOLD" />
<DataTemplate.Triggers>
<DataTrigger Binding="{sold_status}" Value="False">
<Setter TargetName="Status" Property="Text" Value="NOT SOLD"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>

Categories