2

I've noticed in my programs when I have alot of complicated bindings going on then visual studio does not show the xaml properly.

Does MVVM and its numerous bindings cause this? Is the safest way to show xaml in the visual studio designer to remove bindings completely?

Shai UI
  • 50,568
  • 73
  • 204
  • 309
  • 3
    The XAML designer doesn't play terribly well with MVVM. But I would not cut my head off with a chainsaw just because my scalp itched. – 15ee8f99-57ff-4f92-890c-b56153 Apr 26 '17 at 17:05
  • 1
    It's nothing to do with MVVM, rather the XAML designer in VS. The XAML designer in Visual Studio and the child process it spawns is completely buggy and has been for ~3 years now. From annoyances such as **freezing VS; property editors that don't work.** Use Expression Blend instead (if you can that is). I've never had a problem with EB –  Apr 26 '17 at 17:22
  • 4
    Stop using drag/drop and just type XAML. It's 1000x faster, you get much cleaner and clearer markup, and it doesn't suck. –  Apr 26 '17 at 17:36
  • @MickyD: Expression Blend does not exists for years. There is Blend For Visual Studio now. However, Visual Studio uses the same XAML designer as Blend. So what are you talking about? – Liero Apr 26 '17 at 18:20
  • @Will: designer is not about drag&drop. It's about visualisation of what you have written. It's 1000x faster when I see the changes instantly in the designer than to run the application each time. The designer is also extremly helpful when I need to work on views created by somebody else. Without the designer even finding the correct UserControl may be hell if you are not familiar with the project structure – Liero Apr 26 '17 at 20:24
  • 1
    @Liero excuses, excuses. When you get woke and find yourself in the matrix, you're going to be all like "that's just text, I don't see anything, argh, I just got killed by octopus robot" –  Apr 26 '17 at 20:26
  • @Will: not sure what to say :) – Liero Apr 26 '17 at 20:32

2 Answers2

7

No. One of the MVVM core principles is designer support. The principle is called "Blendability" after the Expression Blend designer (resp Blend for Visual Studio) tool. Note, that Visual Studio uses the same designer.

With MVVM you can achieve much better design time support by databinding to design time data. For example, you in DataGrid or ListBox you can see in the designer how the actual items looks like when databound.

Breaking the designer has nothing to do with complexity of bindings.

You just need to follow few simple principles and understand what's going on in the designer.

First of all, Visual Studio designer creates instance of the ViewModel in the designer process. You need to be careful, that you don't execute such code in the viewmodel, that could break the designer. Here are some examples:

Don't do this

  1. This will break the designer, because Visual Studio Designer is not allowed to do DB calls.

    //ctor
    public MyViewModel()
    {
        using(var db = new MyDbContext()} ... //
    }
    

    calling DB, or FileSystem in constuctor is bad practice anyway

  2. this breaks the designer, because VS Designer does not have access to your configuration

    //ctor
    public MyViewModel()
    {
       string configValue = ConfigurationManager.AppSettings["SomeProperty"]
    }
    
  3. if you databind to a property, the getter is acually executed. This code breaks the designer, because App.Current is the Visual Studio Designer, not your app! Be carefull about it.

    public class MyViewModel
    {
       public string SomeProperty
       {
           get { return App.Current.MainWindow.SomeProperty; }
       }
    }
    
  4. This will cause NullReferenceException when binding to CountOfItems, because VS Designer doesn't call Load()

    public class MyViewModel
    { 
       private List<string> _items; 
    
       public void Load()
       {
           _items = new List<string>{ "Item1", "Item2" }
       }
    
    
       public int CountOfItems
       {
           get { return _items.Count; }
       }
    }
    

Good practices

Just check if you are in the design mode wherever needed:

//ctor
public MyViewModel
{
    bool IsDesignMode => DesignerProperties.GetIsInDesignMode(new DependecyObject());

    public MyViewModel()
    {
       if (IsDesignMode)
       {
          //this will be shown in the designer
          Items = new List<string>{ "Item1", "Item2" }
       }
    }

    //INotifyPropertyChanged details ommited due to simplification
    public List<string> Items {get; private set;}

    public void Load()
    {
       //optionally you may check IsDesignMode 
       using (var db = new MyDbContext())
       {  
           this.Items = db.Items.Select(i => i.Name).ToList();
       }
    }
}

I've created code snippet, where I use this pattern:

d:DataContext="{d:DesignInstance Type=local:MyViewModelDesignTime, IsDesignTimeCreatable=True}"

I don't actually instantiace the ViewModel directly, but I inject DesignTime version of the viewmodel:

public class MyViewModel()
{
    protected MyViewModel()
    {
        //both runtime and design time logic. 
        //you may use IsDesignMode check if needed
    }

    public MyViewModel(ISomeExternalResource externalResource) : this();
    {
        //this is executed only at run time
        _externalResource = externalResource;
        Items = externalResouce.GetAll();
    }

    public List<string> Items {get; protected set;}
}

public class MyViewModelDesignTime : MyViewModel
{
    public MyViewModelDesignTime () : base()
    { 
        //this will be show in the designer
        Items = new List<string> { "Item1", "Item2" };
    }
}

If your designer breaks anyway and you don't know why, you can attach another instance of visual studio to the xaml designer process and it will nicelly show the problematic line of code.

Last, but not least, you can easily turn off instanciating the ViewModels. Just set IsDesignTimeCreatable=false in d:DataContext

Recapitulation

  1. Check all the code execution paths of your viewmodel which can be executed by the xaml designer process
  2. Do not access database, webservices or filesystem in those execution paths
  3. Do not access static resource, e.g. Application.Current, because thay may not be initialized properly
  4. Check all getters of properties that are databound. They may trie to return something that was not initialized by the designer.
  5. Use branching (e.g. if..else) for the designer and runtime execution paths
  6. Always generate some fake design-time data
Liero
  • 25,216
  • 29
  • 151
  • 297
  • "Last, but not least, you can easily turn off instanciating the ViewModels. Just set IsDesignTimeCreatable=false in d:DataContext". Alternatively, on the toolbar in the XAML designer, choose the Disable project code button - source: https://learn.microsoft.com/en-us/visualstudio/designers/debugging-or-disabling-project-code-in-xaml-designer – MotKohn Apr 28 '17 at 15:29
  • @MotKohn: The only problem is that the button is often not visible when designer fails :) – Liero Apr 28 '17 at 18:50
  • 1
    Also beware if you are using the `Dispatcher` for `async` tasks. Other than that what a great answer! Well done @Liero – XAMlMAX May 12 '17 at 13:50
  • Big thanks! I've been dealing with this issue for awhile and finally Google'd my way to this answer. – Telos Sep 06 '18 at 21:53
2

Yes if your bindings and Viewmodel are complex there are chances that your design time maynot work. But if you want design time support, then create a dummy viewmodel and you can set it as design time viewmodel which will use the dummy viewmodel only for designtime. Check below code.

d:DataContext="{d:DesignInstance Type=yourviewmodetype, IsDesignTimeCreatable=True}"
Ayyappan Subramanian
  • 5,348
  • 1
  • 22
  • 44