I'm working on a LightSwitch custom control that is able (well, at least this is intended...) to bind to and edit various different properties, based on a discriminating value.
Let me explain a bit further. The table looks like this:
Now, based on the value of Datenformat
, the control binds itself dynamically to ErgebnisBool
, ErgebnisDatum
and so on and selects the appropriate DataTemplate
from the control's xaml
.
ErgebnisAnzeige
is a computed text property that holds a read-only display string.
The control's xaml is as follows:
<UserControl x:Class="EuvControlsExtension.Presentation.Controls.ProzessErgebnisEdit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:framework ="clr-namespace:Microsoft.LightSwitch.Presentation.Framework;assembly=Microsoft.LightSwitch.Client"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:ct="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input"
xmlns:multi="clr-namespace:EuvControlsExtension.Presentation.Controls"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
mc:Ignorable="d"
x:Name="HostControl">
<multi:MtTemplateSelector x:Name="MyTemplateSelector"
Content="{Binding Path=RootEntity, Mode=TwoWay, ElementName=HostControl, UpdateSourceTrigger=Default}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Center"
IsHitTestVisible="False">
<!--Zahl-->
<multi:MtTemplateSelector.ZahlTemplate>
<DataTemplate>
<TextBox HorizontalAlignment="Stretch"
Text="{Binding Path=RootEntity.ErgebnisZahl, ElementName=HostControl, Mode=TwoWay, UpdateSourceTrigger=Default, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/>
</DataTemplate>
</multi:MtTemplateSelector.ZahlTemplate>
<!--Bool-->
<multi:MtTemplateSelector.BoolTemplate>
<DataTemplate>
<CheckBox IsThreeState="True"
Content="{Binding Path=RootEntity.ErgebnisBool, ElementName=HostControl, Mode=TwoWay, UpdateSourceTrigger=Default, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/>
</DataTemplate>
</multi:MtTemplateSelector.BoolTemplate>
</multi:MtTemplateSelector>
</UserControl>
The MtTemplateSelector
class simply returns the appropriate DataTemplate for the current format, nothing special here.
The control itself (ProzessErgebnisEdit
) is also very simple. It does nothing than binding the entity instance (called RootEntity
):
public partial class ProzessErgebnisEdit : UserControl
{
public ProzessErgebnisEdit()
{
InitializeComponent();
BindProperties();
}
private void BindProperties()
{
var binding = new Binding("DataSourceRoot.RootObject")
{
Mode = BindingMode.TwoWay
};
this.SetBinding(RootEntityProperty, binding);
}
public object RootEntity
{
get { return GetValue(RootEntityProperty); }
set { SetValue(RootEntityProperty, value); }
}
public static readonly DependencyProperty RootEntityProperty = DependencyProperty.Register(
"RootEntity",
typeof(object),
typeof(ProzessErgebnisEdit),
new PropertyMetadata(null));
}
Last not least I have this control factory that returns a display-only DataTemplate, when appropriate:
[Export(typeof(IControlFactory))]
[ControlFactory("EuvControlsExtension:ProzessErgebnisEdit")]
internal class ProzessErgebnisEditFactory : IControlFactory
{
private DataTemplate dataTemplate;
private DataTemplate displayModeDataTemplate;
public DataTemplate DataTemplate
{
get {
return this.dataTemplate ??
(this.dataTemplate = XamlReader.Load(ControlTemplate) as DataTemplate);
}
}
public DataTemplate GetDisplayModeDataTemplate(IContentItem contentItem)
{
return this.displayModeDataTemplate ??
(this.displayModeDataTemplate = XamlReader.Load(DisplayModeControlTemplate) as DataTemplate);
}
private const string DisplayModeControlTemplate =
"<DataTemplate" +
" xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>" +
" <Border Background='GreenYellow'>" +
" <TextBlock Text='{Binding Path=DataSourceRoot.RootObject.ErgebnisAnzeige}' Margin='3' Foreground='Red' " +
" TextAlignment=\"{Binding Properties[Microsoft.LightSwitch:RootControl/TextAlignment]}\"" +
" VerticalAlignment=\"{Binding Properties[Microsoft.LightSwitch:RootControl/VerticalAlignment]}\" />" +
" </Border>" +
"</DataTemplate>";
private const string ControlTemplate =
"<DataTemplate" +
" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"" +
" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"" +
" xmlns:ctl=\"clr-namespace:EuvControlsExtension.Presentation.Controls;assembly=EuvControlsExtension.Client\">" +
"<ctl:ProzessErgebnisEdit/>" +
"</DataTemplate>";
}
Everything works fine so far: When the cell is not focused, the display-only text appears (e.g. Wahr/Falsch/--), and when I click to edit a cell, it switches to the approriate DataTemplate (e.g. a Checkbox). And there is always the correct value displayed, which tells me that the databinding generally works.
The only problem is that the controls are always read-only, and I'm not able to make them editable via code or xaml or whatever.
So far I tried to intercept the grid's OnPrepareCellEditing
event and then setting the IsReadOnly
property of the respective column manually to false
, and I also tried the same with the control's DataContext.IsReadOnly
property. No luck...
What am I missing? Is my entire approach flawed? What's going on here? I can't figure out a reason for this behavior, I don't even see a direction for searching...
Edit: On the german identifiers Some of the identifiers are in German und thus might not be immediately clear to everyone. But in the end, it's as simple as this: Ergebnis is German for Result. This expression appears frequently in the table because the value to display is the result of a physical production process which can be of various data types such as bool, string, datetime etc. (nothing fancy here). This information is the content of the Datenformat column, which would be something like DataType in English.
Edit2: The template selector:
public class MtTemplateSelector : DataTemplateSelector
{
public DataTemplate UnknownTemplate { get; set; }
public DataTemplate ZahlTemplate { get; set; }
public DataTemplate FreitextTemplate { get; set; }
public DataTemplate AuswahlTemplate { get; set; }
public DataTemplate BoolTemplate { get; set; }
public DataTemplate DatumTemplate { get; set; }
public DataTemplate MessungTemplate { get; set; }
public DataTemplate DateiPfadTemplate { get; set; }
public DataTemplate OrdnerPfadTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
switch (GetDatenFormatEnum(item))
{
case DatenformatEnum.Zahl:
return ZahlTemplate;
...
You simply need to remove the IsHitTestVisile=False
from the multi:MtTemplateSelector
this prevents it, and all it's children, from getting events from user interactions. You can learn more here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With