Udostępnij za pośrednictwem


Troubleshooting WPF Designer Load Failures

The Windows Presentation Foundation (WPF) Designer for Visual Studio includes a sophisticated and extensible visual designer that renders XAML. If your XAML file does not load in the designer, there are several things that you can do to try to understand what is going wrong. This topic describes some tips and techniques to help you troubleshoot WPF Designer load failures.

Note

Many of the techniques in this topic also apply to Expression Blend.

Troubleshooting Steps

The following steps can help you troubleshoot WPF Designer load failures.

  1. Read any exception messages you receive.

    This may seem obvious, but if you get an exception, clearly read the message. In some cases, it can help you quickly diagnose the problem. For more information see Debugging and Interpreting Errors in the WPF Designer.

  2. Determine if the problem is in your implementation.

    Build and run your application to determine whether the problem is the result of your implementation only, or an interaction with the WPF Designer. If the application builds and runs, the design-time error is likely caused by your implementation.

  3. Use the Visual Studio debugger to step into your code at design time. For more information, see Walkthrough: Debugging WPF Custom Controls at Design Time.

  4. Determine if the problem is a loading error.

    If Design view fails to load because of an exception, the problem is likely a loading error. If you have custom code that is loaded at design time, and you experience exceptions or load failures at design time, see the Writing Code for Design Time section in this topic. If you are working with resources and they do not appear to be loading, see the UserControl and Custom Control Resources at Design Time section in this topic.

  5. Review your code that is loaded at design time.

    There are two approaches to writing code that also runs at design time. The first approach is to write defensive code by checking the input parameters to classes. The second approach is to check whether design mode is active by calling the GetIsInDesignMode method. For more information, see the Writing Code for Design Time section in this topic.

  6. Review other areas of your code.

    Review the Programming Tips section of this topic for some programming tips when you work with the WPF Designer. Review the Programming Best Practicess section of this topic for techniques on how to write more robust code.

  7. If you still have problems, you can use the WPF Designer forum on MSDN to connect with other developers who are using the WPF Designer. To report potential issues or provide suggestions, use the Visual Studio and .NET Framework Feedback site.

Writing Code for Design Time

Ensure that your code runs at design time, as well as run time. If your code runs at design time, do not assume that Application.Current is your application. For example, when you are using Expression Blend, Current is Expression Blend. At design time, MainWindow is not your application's main window. Typical operations that cause a custom control to fail at design time include the following.

There are two approaches to writing code for design time. The first approach is to write defensive code by checking the input parameters to classes, such as value converters. The second approach is to check whether design mode is active by calling the GetIsInDesignMode method.

Checking input parameters for some implementations is necessary because the design environment provides different types for some inputs than those provided by the runtime environment.

Style selectors and value converters usually require one of these approaches to run correctly at design time.

Value Converters

Your custom IValueConverter implementations should check for null and for the expected type in the first parameter of the Convert method. The following XAML shows a binding to Application.Current that fails at design time if the value converter is not implemented correctly.

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

The binding raises an exception at design time because Application.Current refers to the designer application instead of your application. To prevent the exception, the value converter must check its input parameters or check for design mode.

The following code example shows how to check input parameters in a value converter that returns true if two input parameters satisfy particular business logic.

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

The second approach to writing code for design time is to check whether design mode is active. The following code example shows a design-mode check instead of the parameter check shown previously.

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

Style Selectors

Your custom style selectors also must be implemented to run in design mode. The following XAML shows a custom template selector that uses Application.MainWindow at run time to determine which resource is returned as a DataTemplate. At design time, this resource may not be available, so the SelectTemplate override returns null at design time.

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

The following code shows the implementation of the style selector.

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 and Custom Control Resources at Design Time

By default, UserControl and custom control resources that are available at run time may not be available at design time. When you add your custom controls and user controls to a Page or Window on the design surface, an instance of the control is created. Resources in App.xaml are not available to UserControl and custom control instances loaded on a page or window.

To make your resources available at design time, factor them into a separate resource dictionary and include the dictionary in App.xaml and your control's XAML. Change all StaticResource references to DynamicResource references. The following code example shows how to share a resource dictionary so that its resources are available at design time.

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>

Pack URI Syntax

You should not use application-relative resource references. The following code example shows the application-based syntax, which may fail at design time.

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

Such references are relative to the application instead of the DLL. Using an application-relative resource reference in a DLL makes the DLL dependent on resources in the parent application. This approach is fragile and not guaranteed to work at design time.

Instead of using application-relative resource references, add resources to the DLL itself and use component-based resource references. For more information, see Pack URIs in Windows Presentation Foundation.

The following code examples show the component-based syntax, which is the recommended approach.

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

Programming Tips

The following are some programming tips when you work with the WPF Designer.

Programming Best Practices

The following are some programming best practices on how to write more robust code for the WPF Designer.

  • Always wrap editing scopes in using statements or try/finally blocks. If an exception is raised, the change is aborted in the Dispose call. For more information, see ModelEditingScope.

  • Use a ModelEditingScope to move a control from one container to another. Failure to do this raises an exception.

  • In WPF and the WPF Designer, do not set a property value to its default if your intent is to clear it. For NaN values, such as Height, call the ClearValue method instead of assigning NaN.

  • When retrieving values from a property, use the computed value of the property. This means you should use the ComputedValue property instead of the GetCurrentValue method of ModelItem. The GetCurrentValue method returns bindings and other expressions if they were stored in the XAML, so you can get cast exceptions in some cases.

See Also

Other Resources

Debugging and Interpreting Errors in the WPF Designer

XAML and Code Walkthroughs

Basic Extensibility Concepts

Understanding WPF Designer Extensibility