Share via


定義、覆寫和使用 LightSwitch 控制項屬性

LightSwitch 控制項具有可以在設計階段設定值的屬性,或在執行階段呼叫 FindControl 擴充方法傳回代理。有些屬性是於最上層的內建控制項 RootControl 中定義,每個控制項都會隱含繼承這個基礎控制項,因此為內建的,且被所有控制項所繼承。控制項可以定義自己的屬性,可覆寫內建屬性的某些屬性,此外,也可以於屬性特定本身或其子系的值。

LightSwitch 包含會在設計階段及執行階段執行的一個屬性解析系統。這個系統允許螢幕設計工具的屬性工作表知道在內容樹狀結構中的不同點的屬性的預設值,且顯示和它們在執行階段一樣的值。

控制項可管理屬性的預設值以提供更好的預設經驗。例如,預設標籤位置於螢幕 AttachedLabelPosition 設為 Left-aligned 。 AttachedLabelPosition 是可繼承的屬性。 因此它的值會自動傳播至其所有子系,以及它們的子系,直到控制項覆寫該屬性的預設值,或者,直到開發人員變更了內容項目的屬性值。

例如,清單中的值是一般不會顯示標籤。 因此 List 控制項將所有子代的預設標籤位置改為 None。它也會變更本身的預設標籤位置為 Collapsed。開發人員可以在螢幕設計工具或在執行階段變更一或多個預設值,並且變更的值會繼承在內容樹狀結構中,直到另一個控制項指定不同的預設值或開發人員變更其值。

控制項屬性在內容項目節點 IContentItem.Properties的 Properties 集合中。如果屬性於特定項目的執行個體中有效,則會在屬性集合中出現它的條目。 否則則不會。因此,如果因為屬性定義於控制項或於它的祖系,或定義於 RootControl ,或者屬性是可附加的屬性,則 IContentItem.Properties 會包含它的項目。 否則 Properties.TryGetValue 會傳回 False。如果這個值實際上尚未設定,則 Properties.TryGetValue 會成功,不過,集合會傳回 Null 至其值。

定義新的控制屬性。

LightSwitch 控制項使用 ControlProperty 項目, 在方案的 .lsml 中繼資料中定義新的控制項屬性。 下列範例會在名為 MyControl 的控制項定義名為 ShowButton 的屬性。

<Control Name="MyControl" ... >
    ...
    <Control.Properties>
      <ControlProperty 
Name="ShowButton"
PropertyType=":Boolean"
CategoryName="Appearance"
              EditorVisibility="PropertySheet">
        <ControlProperty.Attributes>
          <DisplayName Value="Show Button" />
          <Description Value="Determines whether the button is shown." />
        </ControlProperty.Attributes>
        <ControlProperty.DefaultValueSource>
          <ScreenExpressionTree>
            <ConstantExpression ResultType=":Boolean" Value="True"/>
          </ScreenExpressionTree>
        </ControlProperty.DefaultValueSource>
      </ControlProperty>
    </Control.Properties>
  </Control>

下列是 ControlProperty的可用屬性:

  • PropertyType (必須) – 屬性的型別。只支援簡單的 IDataTypes ,例如“:Int32“:String” 等,以此類推。複雜的屬性資料可以儲存為字串且使用自訂屬性編輯器顯示。

  • IsAttachable - 如為 True,則屬性可能會設定於未定義它的控制項的內容項目中。

  • IsInheritable – 如為 True,屬性的值被內容樹狀結構的子代自動繼承,直到它被覆寫。

    注意事項注意事項

    可繼承的屬性也必須是可附加的;否則,它不會在會繼承它的所有可能的子系有效。

  • CategoryName - 指定分類的名稱,該分類會將屬性以群組方式顯示在螢幕設計工具的屬性視窗中。目前可用的選項是空白或 Default、 Validation、 Appearance和 Sizing。

  • UIEditorId – 指定使用的屬性工作表編輯器: 內建或自訂。如果未指定,則會根據屬性型別決定使用的預設編輯器。

  • EditorVisibility - 指示在設計階段中屬性的處理方式。

    • NotDisplayed (預設) - 此屬性在屬性工作表不會顯示。

    • PropertySheet - 使用指定的 (或預設) 屬性工作表編輯器顯示屬性工作表。

  • AttachedPropertyAvailability - 表示附加屬性的可用性。如果屬性不是可附加的,將被忽略。

    • Default – 附加屬性為在樹狀結構中的所有內容項目可用。

    • ImmediateChildren – 附加屬性只有在控制項的內容樹狀結構的直接子內容項目為有效。

  • DefaultValueSource – 為這個屬性提供預設值的運算式,必須是常數。

  • IsReadOnly – 如為 True,代表值無法被開發人員變更。

管理編輯器和檢視器控制項的屬性。

一般來說會擁有兩套控制項 – 一個是會啟用編輯資料 — editor —,一個只顯示資料 — viewer —。範例包含 AddressEditor/AddressViewer 和 TextBox/Label。 實作一對控制項於主題 其他 LightSwitch 控制項概念 中的〈提供編輯器和檢視器控制項〉一節。

覆寫屬性

控制項的屬性定義被所有子系控制項繼承。使用 PropertyOverride 項目,控制項可以覆寫繼承的屬性的某些屬性。

例如,繼承自 RootControl的 VerticalAlignment 屬性的所有控制項。下列範例顯示當該控制項使用 VerticalAlignment ,或從它衍生的控制項,控制項也可以覆寫它的預設值。

<Control Name="MyControl" ... >
    ...
    <Control.PropertyOverrides>
      <ControlPropertyOverride
          Property=":RootControl/Properties[VerticalAlignment]">
        <ControlPropertyOverride.DefaultValueSource>
          <ScreenExpressionTree>
            <ConstantExpression ResultType=":String" Value="Top"/>
          </ScreenExpressionTree>
        </ControlPropertyOverride.DefaultValueSource>
      </ControlPropertyOverride>
    </Control.PropertyOverrides>
  </Control>

下列是 ControlPropertyOverride的可用屬性:

  • Property (必要) - 指定屬性的完整 ID 以覆寫。

  • DefaultValueSource – 已覆寫的預設值。

  • UIEditorId – 已覆寫的編輯器 ID.

  • IsReadOnly – IsReadOnly 屬性的覆寫值。

支援在擴充控制項的內建通用屬性

LightSwitch 定義了一組經常在 RootControl 有用的屬性。有些屬性是由 LightSwitch 自動支援並在新控制項的屬性工作表自動出現。LightSwitch 通常也自動處理這些屬性的功能。 因此,雖然可能有控制項可以設定的選項,控制項不需要做任何動作以支援屬性。您可以選擇設定 EditorVisibility 至 [NotDisplayed] ,以從控制項的屬性工作表中隱藏屬性。

要求控制項執行某項行為的屬性—例如繫結至 XAML—預設從屬性工作表隱藏。若要支援這些,擴充功能控制項必須實作必要的行為以及覆寫 EditorVisibility 至 PropertySheet。下列章節包含通用屬性和如何從您的控制項支援它們。

Opt-out 控制項屬性 (預設會顯示)

預設情況下 Opt-out 屬性在屬性工作表為啟用,同時有 LightSwitch 提供給控制項的自動行為。

  • AttachedLabelPosition (可繼承) - LightSwitch 會自動顯示已有預設值的擴充控制項的標籤。這可能對某些控制項來說有好處,例如讓 Button 控制項顯示自己的附加標籤。在這種情況下,將控制項的 AttachedLabelSupport 屬性設為 DisplayedByControl,如下所示。

    <Control Name="MyCheckBox"
               AttachedLabelSupport="DisplayedByControl"
        ... />
    

    您也可以藉由覆寫 EditorVisibility以隱藏 AttachedLabelPosition屬性。只覆寫 EditorVisibility 為 NotDisplayed 不夠,因為即使屬性在屬性工作表未顯示,其值依然繼承自父系,如果 AttachedLabelSupport 保留為預設值 DisplayedByContainer,LightSwitch 將自動顯示適當的標籤。

  • 常見的調整大小屬性:

    • HeightSizingMode

    • WidthSizingMode

    • MinHeight

    • MaxHeight

    • MinWidth

    • MaxWidth

    • Height

    • Width

    這些屬性都是由與 HeightSizingMode 屬性關聯的單一編輯器顯示。 在大部分情況下,建議您在的屬性工作表保留這些啟用以保持一致性,因為 LightSwitch 在一般案例都自動處理控制項的大小控制。

    如果因為某些原因控制項必須隱藏這些屬性,您應該覆寫 HeightSizingMode 的 EditorVisibility 屬性為 NotDisplayed,如下所示。

    <!--Hide all of the common sizing properties by hiding HeightSizingMode-->  
          <ControlPropertyOverride Property=":RootControl/Properties[HeightSizingMode]"
                                   EditorVisibility="NotDisplayed">
    
  • Rows 和 Characters

    這些實際上並不是通用屬性。不過,如果您的控制項定義了使用這些名稱的屬性,一般大小屬性編輯器也會顯示它們。它們的 EditorVisibility 屬性應該要被設為 NotDisplayed ,以便 LightSwitch 不顯示它們的其他編輯器。例如:

    <Control Name="MyTextBox" ... >
        ...
        <Control.Properties>
          <ControlProperty Name="Lines"
                           PropertyType=":Int32"
                           CategoryName="Sizing"
                           EditorVisibility="NotDisplayed">
            <ControlProperty.Attributes>
              <DisplayName Value="$(MyTextBox_Lines_DisplayName)" />
              <Description Value="$(MyTextBox_Lines_Description)" />
            </ControlProperty.Attributes>
            <ControlProperty.DefaultValueSource>
              <ScreenExpressionTree>
                <ConstantExpression ResultType=":Int32" Value="1"/>
              </ScreenExpressionTree>
            </ControlProperty.DefaultValueSource>
          </ControlProperty>
    
          <ControlProperty Name="Characters"
                           PropertyType=":Int32"
                           CategoryName="Sizing"
                           EditorVisibility="NotDisplayed">
            <ControlProperty.Attributes>
              <DisplayName Value="$(TextBox_Characters_DisplayName)" />
            </ControlProperty.Attributes>
            <ControlProperty.DefaultValueSource>
              <ScreenExpressionTree>
                <ConstantExpression ResultType=":Int32" Value="1"/>
              </ScreenExpressionTree>
            </ControlProperty.DefaultValueSource>
          </ControlProperty>      
    
        </Control.Properties>
    
  • 一般對齊屬性:

    • HorizontalAlignment

    • VerticalAlignment

    這些屬性都是由與 VerticalAlignment 屬性關聯的單一編輯器顯示。若要隱藏它們,雖然通常不建議這麼做,請覆寫 VerticalAlignment 的 EditorVisibility 屬性為 NotDisplayed。

    類似於 Rows 和 Characters,如果擴充控制項以 WeightedRowHeight 和 WeightedRowWidth 的名稱定義自己的屬性 , 它們也會由這個編輯器顯示。

Opt-in 控制項屬性

Opt-in 屬性預設也在屬性工作表隱藏,因為 LightSwitch 不能為控制項自動提供其行為,或因為並非所有的控制項需要這項功能。Opt-in 屬性可被覆寫以在屬性工作表中顯示,但是,可能需要在控制項屬性做額外工作才可以有您想要的效果。

  • ShowAsLink

    若要支援這個屬性,請先覆寫在控制項之中繼資料的 EditorVisibility="PropertySheet" :

    <Control.PropertyOverrides>
          <!-- Support Show As Link property -->
          <ControlPropertyOverride
            Property=":RootControl/Properties[ShowAsLink]"
            EditorVisibility="PropertySheet"/>
    </Control.PropertyOverrides>
    

    使用在您的控制項的視覺化樹狀中的內建展示架構控制項 LinkableLabel (Microsoft.LightSwitch.Presentation.Framework.LinkableLabel) 以有 automatic label-or-hyperlink 行為,如同 Label。 或者,使用您的 UI 並使用在 Helper 類別 ShowAsLinkPropertyHelper 中的函式 (Microsoft.LightSwitch.Presentation.Framework.Helpers.ShowAsLinkPropertyHelper) 以實作這項功能。

  • FontStyle (可繼承)

    若要支援 FontStyle,這只建議給唯讀控制項 Label 使用,只需覆寫它的 EditorVisibility 至 PropertySheet,而它的功能會由 LightSwitch自動處理。

  • TextAlignment

    若要支援 TextAlignment,控制項必須覆寫 EditorVisibility 並提供它的實作,如下所示。

    <TextBox
           Text="{Binding StringValue, Mode=TwoWay}"
           TextAlignment="{Binding Properties[MyControlExtension:MyControl/TextAlignment]}"
           IsReadOnly="{Binding IsReadOnly}"
           AutomationProperties.AutomationId="{Binding Name, StringFormat=Control: \{0\}}"
           AutomationProperties.Name="{Binding DisplayName}"
           AutomationProperties.HelpText="{Binding Description}"
           ToolTipService.ToolTip="{Binding Description}"
       />
    
  • BrowseOnly (可繼承)

    這個屬性對應至屬性工作表的 [使用唯讀控制項] 屬性。若要支援此功能,僅建議給群組和智慧型配置控制項使用,覆寫 EditorVisibility 到 PropertySheet ,而 LightSwitch 會自動處理它。

  • IsReadOnly (可繼承) 和 IsEnabled (可繼承)

    這兩個屬性僅供內部使用,不應該顯示在屬性工作表。

  • ContainerState (可繼承)

    ContainerState 是不應該顯示在屬性工作表的內部屬性。 它可讓控制項根據內容樹狀結構變更其 UI 或行為。 目前唯一定義的標準值為 None 和 Cell。  Cell 表示控制項被其它將項目表示為單元的控制項內使用 (例如,DataGrid)。例如,當 ContainerState 為 Cell,內建 TextBox 控制項變更其外觀。

    如果您建立集合或群組控制項且要如 DataGrid 具有變更外觀的控制項,在控制項的子控制項設定這個屬性的值為 Cell ,如下所示。

    <Control.ChildItemPropertySources>
          <!-- Set ContainerState for descendants to "Cell", so they can draw 
               themselves differently inside a DataGrid or similar control -->
          <ControlPropertySource Property=":RootControl/Properties[ContainerState]">
            <ControlPropertySource.Source>
              <ScreenExpressionTree>
                <ConstantExpression ResultType=":String" Value="Cell" />
              </ScreenExpressionTree>
            </ControlPropertySource.Source>
          </ControlPropertySource>
        </Control.ChildItemPropertySources>
    

    如果您建立變更其行為以回應其 ContainerState的控制項,您可以檢查 IContentItem.ContainerState,或者從 IContentItem.Properties 尋找,而以程式碼回應或透過視覺化狀態以 XAML回應。

  • Image

    若要支援 Image 屬性,控制項必須覆寫 EditorVisibility 到 PropertySheet 並將 UI 繫結到 Image。請勿直接繫結至 Image 屬性的值。相反地,您應該使用在 Microsoft.LightSwitch.Presentation.Framework.Helpers 的 Helper 類別 ImagePropertyHelper 以將屬性設定譯為 IContentItem 並且擷取正確的影像以顯示。Helper 類別知道如何擷取影像和取得給特定繫結資料的正確預設影像,例如按鈕方法。

列舉數值的屬性。

因為屬性型別必須是 IDataType 型別,而 LightSwitch 目前不支援列舉型別,值是來自已知的列舉屬性值的屬性必須儲存為字串。在檢查屬性值時,控制項必須進行任何必要的轉換。

如果已特定 SupportedValue 和 SupportedValuesExclusive 屬性,字串的預設屬性編輯器可以處理列舉數值的屬性,並以數值顯示 ComboBox 。例如:

<ControlProperty Name="TextAlignment"
                       PropertyType=":String"
                       CategoryName="Appearance"
                       EditorVisibility="PropertySheet">
        <ControlProperty.Attributes>
          <DisplayName Value="$(MyControl_TextAlignment_DisplayName)" />
          <Description Value="$(MyControl_TextAlignment_Description)" />
          <SupportedValuesExclusive />
          <SupportedValue DisplayName="$(TextAlignment_StandardValues_Left)" 
                          Value="Left" />
          <SupportedValue DisplayName="$(TextAlignment_StandardValues_Right)" 
                          Value="Right" />
          <SupportedValue DisplayName="$(TextAlignment_StandardValues_Center)" 
                          Value="Center" />
        </ControlProperty.Attributes>
        <ControlProperty.DefaultValueSource>
          <ScreenExpressionTree>
            <ConstantExpression ResultType=":String" Value="Left"/>
          </ScreenExpressionTree>
        </ControlProperty.DefaultValueSource>
      </ControlProperty>

自動設定屬性值

控制項可以直接從中繼資料在其和 (或) 其子系自動設定屬性值。控制項可以在下列位置設定屬性:

  • Control.PropertySources - 直接在控制項設定屬性值。

  • Control.ChildItemPropertySources - 設定控制項的所有子內容項目的屬性值。

  • Placeholder.PropertySources - 在特定控制項替代符號的內容項目子系中設定屬性值。

下列範例顯示正在執行的全部三個屬性來源。

<Control Name="MySmartLayout"
           SupportedContentItemKind="Group">

    <!-- Set property values on the control itself -->
    <Control.PropertySources>
      <!-- Override AttachedLabelPosition on the control itself to Collapsed – 
            this is the label that is shown for the smart layout itself. 
            Note that this value will also be propagated to all children 
            by default because this property is inheritable, except that you are 
            setting a different value for the children below. -->
      <ControlPropertySource Property=":RootControl/Properties[AttachedLabelPosition]">
        <ControlPropertySource.Source>
          <ScreenExpressionTree>
            <ConstantExpression ResultType=":String" Value="Collapsed" />
          </ScreenExpressionTree>
        </ControlPropertySource.Source>
      </ControlPropertySource>

    </Control.PropertySources>

    <!-- Set property values on all direct children in the content tree -->
    <Control.ChildItemPropertySources>
      
      <!-- Set default AttachedLabelPosition to None for all of the children. -->
      <ControlPropertySource Property=":RootControl/Properties[AttachedLabelPosition]">
        <ControlPropertySource.Source>
          <ScreenExpressionTree>
            <ConstantExpression ResultType=":String" Value="None" />
          </ScreenExpressionTree>
        </ControlPropertySource.Source>
      </ControlPropertySource>
      
    </Control.ChildItemPropertySources>

    <!-- Define two placeholders (or “buckets”).  You will set a value for the
         property FontSize in only one of the placeholders. This value will be
         applied to whatever content item is in that placeholder in the content
         tree. -->
    <Control.Placeholders>
      <Placeholder DisplayName="$(MySmartLayout_Title_DisplayName)" 
                   Name="Title">
        <Placeholder.PropertySources>
          <ControlPropertySource Property=":RootControl/Properties[FontStyle]">
            <ControlPropertySource.Source>
              <ScreenExpressionTree>
                <ConstantExpression ResultType=":String" Value="Heading1" />
              </ScreenExpressionTree>
            </ControlPropertySource.Source>
          </ControlPropertySource>
        </Placeholder.PropertySources>
      </Placeholder>
      <Placeholder DisplayName="$(MySmartLayout_Description_DisplayName)" 
                   Name="Description" />
    </Control.Placeholders>

    ...
  </Control>

在通例,覆寫控制項屬性的預設值以及使用 Control.PropertySources 設定控制項的屬性值之間沒有真正的差異。不過,Placerholder.PropertySources 和 Control.ChildItemPropertySources 並不能說是相同的,因為値不是傳播的。

屬性評估

個別內容項目的屬性值可能來自不同來源。下列是來源的評估順序,從最低到最高優先權:

  1. ControlProperty 中指定的預設值為內容項目的控制項所定義或繼承。

  2. 這個屬性的值由父代有效值繼承而來,如果它是可繼承的。

  3. 由 ControlPropertyOverride覆寫的預設值。

  4. 在控制項的 PropertySources指定的值。

  5. 在父控制項的 ChildItemPropertySources指定的值。

  6. 在父控制項的替代符號的 PropertySources 指定的值,如果値已在替代符號中指定。

  7. 開發人員在設計階段設定的值,ContentItem.PropertySources。

  8. 開發人員在執行階段透過 FindControl() 設定的值。

  9. 內容項目所決定的可變更狀態;對於屬性,例如 IsReadOnlyIsEnabled,覆寫控制項之屬性的 IsReadOnly 方法,依此類推。

  10. 從已繫結的資料之結構描述的狀態,例如唯讀資料表,計算欄位,依此類推。

前六個項目是預設值或在中繼資料中設定的值,項目七和八是 LightSwitch 開發人員設定的值,項目九和十是資料繫結狀態取決於的值。

存取屬性值

繫結 XAML 中的屬性值。

使用完整名稱,則屬性值可能從內容項目的 Properties 集合進行存取。若要避免歧意,屬性字典中記錄屬性的完整名稱。由於在 XAML 繫結附註的限制,標準屬性 ID 例如 “:RootControl/Properties[AttachedLabelPosition]” 無法使用。 因此,使用替代附註以進入 Properties 集合: Microsoft.LightSwitch:RootControl/AttachedLabelPosition。請注意 “Microsoft.LightSwitch” 的捷徑 “:” 無法在這裡使用。以下範例說明此語法。

TextAlignment="{Binding Properties[Microsoft.LightSwitch:RootControl/TextAlignment]}"

從程式碼存取屬性值

您也可以從程式碼存取屬性值。在這種情況下,仍然需要完整的屬性名稱。以下範例將說明如何存取這個屬性值:

Friend NotInheritable Class MyContentItemExtensions
    Private Sub New()
    End Sub

    <System.Runtime.CompilerServices.Extension> _
    Public Shared Function TryGetPropertyValue(Of T)(contentItem As IContentItem, qualifiedPropertyName As String, ByRef value As T) As Boolean
        Dim objValue As Object
        If contentItem.Properties.TryGetValue(qualifiedPropertyName, objValue) AndAlso objValue IsNot Nothing Then
            If GetType(T).IsEnum Then
                Try
                    Dim objectEnumValue As Object = [Enum].Parse(GetType(T), DirectCast(objValue, String))
                    value = DirectCast(objectEnumValue, T)
                    Return True
                Catch generatedExceptionName As ArgumentException
                End Try
            Else
                value = DirectCast(objValue, T)
                Return True
            End If
        End If

        value = Nothing
        Return False
    End Function

    <System.Runtime.CompilerServices.Extension> _
    Public Shared Function GetPropertyValueOrDefault(Of T)(contentItem As IContentItem, qualifiedPropertyName As String, Optional defaultValue As T = Nothing) As T
        Dim result As T
        If contentItem.TryGetPropertyValue(Of T)(qualifiedPropertyName, result) Then
            Return result
        Else
            Return defaultValue
        End If
    End Function
End Class
internal static class MyContentItemExtensions
{
        public static bool TryGetPropertyValue<T>(this IContentItem contentItem, string qualifiedPropertyName, out T value)
        {
            object objValue;
            if (contentItem.Properties.TryGetValue(qualifiedPropertyName, out objValue) && objValue != null)
            {
                if (typeof(T).IsEnum)
                {
                    try
                    {
                        object objectEnumValue = Enum.Parse(typeof(T), (string)objValue), false;
                        value = (T)objectEnumValue;
                        return true;
                    }
                    catch (ArgumentException)
                    {
                    }
                }
                else
                {
                    value = (T)objValue;
                    return true;
                }
            }

            value = default(T);
            return false;
        }

        public static T GetPropertyValueOrDefault<T>(this IContentItem contentItem, string qualifiedPropertyName, T defaultValue = default(T))
        {
            T result;
            if (contentItem.TryGetPropertyValue<T>(qualifiedPropertyName, out result))
                return result;
            else
                return defaultValue;
        }
}

處理屬性變更。

當從程式碼存取屬性值時,您必須使用 IContentItem.PropertyChanged 事件以正確處理屬性變更,它會對屬性或者有效的屬性名稱產生事件。這對所有屬性很重要,因為開發人員可以於執行階段變更屬性值透過 FindControl() 或透過執行階段螢幕設計工具, 「自定螢幕」。通常,如果控制項正確處理執行階段螢幕設計工具中的屬性變更,它會正確地處理 FindControl() 案例。

請參閱

工作

如何:建立 LightSwitch 控制項

逐步解說:建立值控制項擴充功能

逐步解說:建立詳細資料控制項擴充功能

逐步解說:建立智慧版面配置控制項擴充功能

逐步解說:建立堆疊面板控制項擴充功能

概念

Visual Studio 2013 的 LightSwitch 擴充性工具組