【问题标题】:Why is my custom control always read-only?为什么我的自定义控件总是只读的?
【发布时间】:2014-02-27 15:57:30
【问题描述】:

我正在开发一个 LightSwitch 自定义控件,该控件能够(嗯,至少这是有意的......)根据一个可区分的值绑定和编辑各种不同的属性。

让我进一步解释一下。该表如下所示:

现在,基于Datenformat 的值,控件将自身动态绑定到ErgebnisBoolErgebnisDatum 等,并从控件的xaml 中选择适当的DataTemplateErgebnisAnzeige 是一个计算文本属性,它包含一个只读显示字符串。

控件的xaml如下:

<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> 

MtTemplateSelector 类只是为当前格式返回适当的 DataTemplate,这里没什么特别的。

控件本身(ProzessErgebnisEdit)也很简单。它只是绑定实体实例(称为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));
}

最后一点,我有这个控件工厂,它在适当的时候返回一个只显示的 DataTemplate:

[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>";
}

到目前为止一切正常:当单元格未聚焦时,仅显示文本出现(例如 Wahr/Falsch/--),当我单击编辑单元格时,它切换到适当的 DataTemplate(例如 a复选框)。并且总是显示正确的值,这告诉我数据绑定通常有效。

唯一的问题是控件始终是只读的,我无法通过代码或 xaml 或其他方式使它们可编辑。

到目前为止,我尝试拦截网格的OnPrepareCellEditing 事件,然后手动将相应列的IsReadOnly 属性设置为false,我也尝试了与控件的DataContext.IsReadOnly 属性相同的操作。运气不好...

我错过了什么?我的整个方法有缺陷吗?这里发生了什么?我无法弄清楚这种行为的原因,我什至看不到搜索的方向......

编辑:关于德语标识符 一些标识符是德语的,因此可能不是每个人都立即清楚。但最后,就这么简单:Ergebnis 是德语的Result。这个表达式经常出现在表格中,因为要显示的值是物理生产过程的结果,它可以是各种数据类型,如布尔、字符串、日期时间等(这里没什么特别的)。此信息是 Datanformat 列的内容,类似于英文的 DataType

Edit2:模板选择器:

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;

        ...

【问题讨论】:

  • 您能否尝试翻译一些德语(?),因为如果不与您共享该语言,就很难理解您的意图和含义。另外,您的问题是否同时出现在 CheckBox 和 TextBox 上?你对只读是什么意思? IsReadOnly 属性为 True,或者您的更改未对基础 ViewModel 进行?
  • 所以 IsEnabled=False 是您的问题?
  • 您应该在您的控件中调试并检查 IsEnabledCore 的值。您尝试做的事情是使用 CustomControl 而不是 UserControl 更好地完成,这是制作新的和可重用控件的方式。您可能也应该共享 MtTemplateSelector 类,为什么要设置 IsHitTestVisible=False?
  • @Zache IsEnabled/IsEnabledCore 都是“真”——我已经调试过了。关于其他事情:我继承了几乎所有这些代码,我不想在不知道发生了什么的情况下更改它。我在问题中添加了 MtTemplateSelector 类,但正如我所说,它非常简单,我很确定它没有参与问题。
  • 那么控件不是“灰显”的吗?那么 IsHitTestEnalbed=False 应该是您的问题,它会阻止控件(及其子控件)接收用户输入。

标签: c# xaml visual-studio-lightswitch


【解决方案1】:

您只需从multi:MtTemplateSelector 中删除IsHitTestVisile=False,这可以防止它及其所有子项从用户交互中获取事件。你可以了解更多here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多