WPF 設計工具載入失敗移難排解

更新:2007 年 11 月

Windows Presentation Foundation (WPF) Designer for Visual Studio 包含精細且可延伸的視覺化設計工具以供呈現 XAML。如果您的 XAML 檔案沒有載入到設計工具中,有幾種方式可以讓您試著去了解是什麼地方出了問題。本主題將說明一些秘訣和技巧,協助您針對 WPF 設計工具載入失敗進行疑難排解。

注意事項:

本主題提供的許多技巧也同樣適用於 Expression Blend。

疑難排解步驟

下列步驟可協助您針對 WPF 設計工具載入失敗進行疑難排解。

  1. 閱讀所收到的任何例外狀況訊息。

    這似乎是顯而易見的步驟,但是如果您收到例外狀況,請詳讀訊息。在某些情況下,這可幫助您快速診斷問題。如需詳細資訊,請參閱 WPF 設計工具的錯誤偵錯和解譯

  2. 判斷問題是否出於實作 (Implementation)。

    建置並執行應用程式,判斷問題只是實作導致的,還是出於與 WPF 設計工具的互動。如果應用程式能夠建置並執行,則設計階段錯誤可能是實作造成的。

  3. 使用 Visual Studio 偵錯工具,在設計階段逐步執行程式碼。如需詳細資訊,請參閱逐步解說:在設計階段偵錯 WPF 自訂控制項

  4. 判斷問題是否為載入錯誤。

    如果 [設計] 檢視因例外狀況而無法載入,問題可能就是載入錯誤。如果您有自訂程式碼在設計階段載入,而在設計階段發生例外狀況或載入失敗,請參閱本主題的撰寫設計階段的程式碼一節。如果您使用資源而這些資源並未載入,請參閱本主題的設計階段的 UserControl 和自訂控制項資源一節。

  5. 檢視在設計階段載入的程式碼。

    撰寫也能在設計階段執行的程式碼有兩種方式。第一種方式是藉由檢查類別的輸入參數,來撰寫防衛性程式碼。第二種方式則是藉由呼叫 GetIsInDesignMode 方法,檢查設計模式是否為作用中。如需詳細資訊,請參閱本主題的撰寫設計階段的程式碼一節。

  6. 檢視程式碼的其他地方

    請參閱本主題的程式設計提示一節,以了解使用 WPF 設計工具的一些程式設計提示。請參閱本主題的程式設計最佳實務一節,了解如何撰寫更穩固程式碼的技巧。

  7. 如果仍有問題,您可以使用 MSDN 上的 WPF 設計工具論壇,與其他使用 WPF 設計工具的開發人員交流。若要報告可能的問題或提供建議,請使用 Visual Studio and .NET Framework 意見網站。

撰寫設計階段的程式碼

確定您的程式碼能在設計階段和執行階段執行。如果您的程式碼在設計階段執行,請不要假設 Application.Current 是您的應用程式。例如,當您使用 Expression Blend 時,Current 是 Expression Blend。在設計階段,MainWindow 不是您應用程式的主視窗。導致自訂控制項在設計階段失敗的常見作業包括下列幾項。

撰寫設計階段的程式碼有兩種方式。第一種方式是藉由檢查類別的輸入參數,例如值轉換子,來撰寫防衛性程式碼。第二種方式則是藉由呼叫 GetIsInDesignMode 方法,檢查設計模式是否為作用中。

檢查某些實作的輸入參數之所以必要,是因為設計環境為某些輸入提供的型別與執行階段環境提供的不同。

樣式選取器和值轉換子通常需要使用上述其中一種方式,才能在設計階段正常執行。

值轉換子

您的自訂 IValueConverter 實作應檢查 Convert 方法的第一個參數是否有 null 和必要的型別。下列 XAML 顯示 Application.Current 的繫結,如果值轉換子未正確實作,該繫結就會在設計階段失敗。

<ComboBox.IsEnabled>
    <MultiBinding Converter="{StaticResource specialFeaturesConverter}">
        <Binding Path="CurrentUser.Rating" Source="{x:Static Application.Current}"/>
        <Binding Path="CurrentUser.MemberSince" Source="{x:Static Application.Current}"/>
    </MultiBinding>
</ComboBox.IsEnabled>

繫結會在設計階段引發例外狀況,因為 Application.Current 參考的是設計工具應用程式,而非您的應用程式。若要避免這個例外狀況,值轉換子就必須檢查其輸入參數或檢查是否處於設計模式。

下列程式碼範例顯示檢查傳回 true 的值轉換子中的輸入參數,確定兩個輸入參數是否符合特定商務邏輯。

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    // Check the values array for correct parameters.
    // Designers may send null or unexpected values.
    if (values == null || values.Length < 2) return false;
    if (!(values[0] is int)) return false;
    if (!(values[1] is DateTime)) return false;

    int rating = (int)values[0];
    DateTime date = (DateTime)values[1];

    // If the user has a good rating (10+) and has been a member for 
    // more than a year, special features are available.
    if((rating >= 10) && 
        (date.Date < (DateTime.Now.Date - new TimeSpan(365, 0, 0, 0))))
    {
        return true;
    }
    return false;
}

第二種撰寫設計階段程式碼的方式是檢查設計模式是否為作用中。下列程式碼範例顯示設計模式檢查,而非前面顯示的參數檢查。

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    // Check for design mode. 
    if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue)) 
    {
        return false;
    }

    int rating = (int)values[0];
    DateTime date = (DateTime)values[1];

    // If the user has a good rating (10+) and has been a member for 
    // more than a year, special features are available.
    if((rating >= 10) && 
        (date.Date < (DateTime.Now.Date - new TimeSpan(365, 0, 0, 0))))
    {
        return true;
    }
    return false;
}

樣式選取器

您的自訂樣式選取器也必須實作,以在設計模式中執行。下列 XAML 顯示自訂樣板選取器,它在執行階段使用 Application.MainWindow 來判斷哪個資源以 DataTemplate 傳回。在設計階段,這個資源可能無法使用,因此 SelectTemplate 覆寫會在設計階段傳回 null。

<local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>
<ListBox Width="400" Margin="10"
    ItemsSource="{Binding Source={StaticResource myTodoList}}"
    ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
    HorizontalContentAlignment="Stretch" 
    IsSynchronizedWithCurrentItem="True"/>

下列程式碼示範樣式選取器的實作。

public class TaskListDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(
        object item, 
        DependencyObject container)
    {
        if (item != null && item is Task)
        {
            Task taskitem = item as Task;
            Window window = Application.Current.MainWindow;

            // To run in design mode, either test for the correct window class
            // or test for design mode.
            if (window.GetType() == typeof(Window1))
            // Or check for design mode: 
            //if (!DesignerProperties.GetIsInDesignMode(window))
            {
                if (taskitem.Priority == 1)
                return window.FindResource("importantTaskTemplate") as DataTemplate;
                else
                return window.FindResource("myTaskTemplate") as DataTemplate;
            }
        }
        return null;
    }
}

設計階段的 UserControl 和自訂控制項資源

根據預設,UserControl 和在執行階段可用的自訂控制項資源,在設計階段不一定可用。當您將自訂控制項和使用者控制項加入到設計介面上的 PageWindow 時,會建立該控制項的執行個體。載入頁面或視窗的 UserControl 和自訂控制項執行個體無法使用 App.xaml 中的資源。

若要讓資源在設計階段可供使用,請將它們放入另一個資源字典,然後將該字典包含在 App.xaml 和控制項的 XAML 中。將所有 StaticResource 參考變更為 DynamicResource 參考。下列程式碼範例顯示如何共用資源字典,讓其中的資源得以在設計階段使用。

UserControl1.xaml

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

App.xaml

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

封裝 URI 語法

您不應該使用相對應用程式的資源參考。下列程式碼範例示範以應用程式為基礎的語法,這可能會在設計階段失敗。

<Image Name="image1" Source="pack://application:,,,/Image1.bmp" />

上面的參考相對於應用程式而非 DLL。在 DLL 中使用相對應用程式的資源參考會使 DLL 相依於父應用程式中的資源。這種方式並不穩固,且不保證能在設計階段運作。

請不要使用相對應用程式的資源參考,而是將資源加入至 DLL 本身,並使用以元件為基礎的資源參考。如需詳細資訊,請參閱 Windows Presentation Foundation 中的 Pack URI

下列程式碼範例示範以元件為基礎的語法,這是建議的方式。

<Image Name="image1" Source="/TestHostApp;component/Image1.bmp" />
<Image Name="image1" Source="pack://application:,,,/TestHostApp;component/Image1

程式設計提示

下面是一些使用 WPF 設計工具的程式設計提示。

程式設計最佳實務

下面是一些程式設計最佳實務,說明如何為 WPF 設計工具撰寫更穩固的程式碼。

  • 請一律將編輯範圍放在 using 陳述式或 try/finally 區塊內。如果引發例外狀況,會在 Dispose 呼叫中止變更。如需詳細資訊,請參閱 ModelEditingScope

  • 使用 ModelEditingScope,將控制項從一個容器移至另一個容器。未能這麼做會引發例外狀況。

  • 在 WPF 和 WPF 設計工具中,如果要清除某個屬性值,請不要將它設為預設值。針對 NaN 值 (例如 Height),請呼叫 ClearValue 方法來代替指派 NaN。

  • 從屬性擷取值時,請使用屬性的計算值。這表示您應使用 ComputedValue 屬性,而非 ModelItemGetCurrentValue 方法。GetCurrentValue 方法會傳回繫結和其他以 XAML 儲存的運算式,因此在某些情況下可能會發生轉型例外狀況。

請參閱

其他資源

WPF 設計工具的錯誤偵錯和解譯

XAML 和程式碼逐步解說

基本擴充性概念

了解 WPF 設計工具擴充性