admin管理员组

文章数量:1289529

I need my SharedViewModel to be set in design time to display data in my UI

as I run the app, I see data on the screen, because OnLoaded runs LoadStuffs

LoadStuffs initiates the SharedViewModel and creates data

but at design time after a rebuild, nothing show up in the designer

<Window x:Class="MyApp.MainWindow"
        mc:Ignorable="d"
        xmlns:local="clr-namespace:MyApp"
        ...
        Loaded="OnLoaded"
        d:DataContext="{Binding RelativeSource={RelativeSource Self}, Path=SharedViewModel}"
    >

At runtime, these get executed

    void OnLoaded(object sender, RoutedEventArgs e)
    {
        LoadStuffs();
    }

    private void LoadStuffs()
    {
        Logger.Log("LoadStuffs() executed!");
        ...
        SharedViewModel = ...
    }

The message "LoadStuffs() executed!" only appears at runtime, never in design

The property of the main class :

private SharedViewModel m_sharedViewModel;
public SharedViewModel SharedViewModel
{
    set
    {
        m_sharedViewModel= value;
    }
    get
    {
        Logger.Log("SharedViewModel getter"); <<<<< this is never called as the log.txt is only created at runtime
        if (m_sharedViewModel == null)
        {
            Logger.Log("Initializing DesignSharedViewModel");
            LoadStuffs();  // Initializes m_sharedViewModel
        }
        return m_sharedViewModel;
    }
}

Thanks for your help on this

I need my SharedViewModel to be set in design time to display data in my UI

as I run the app, I see data on the screen, because OnLoaded runs LoadStuffs

LoadStuffs initiates the SharedViewModel and creates data

but at design time after a rebuild, nothing show up in the designer

<Window x:Class="MyApp.MainWindow"
        mc:Ignorable="d"
        xmlns:local="clr-namespace:MyApp"
        ...
        Loaded="OnLoaded"
        d:DataContext="{Binding RelativeSource={RelativeSource Self}, Path=SharedViewModel}"
    >

At runtime, these get executed

    void OnLoaded(object sender, RoutedEventArgs e)
    {
        LoadStuffs();
    }

    private void LoadStuffs()
    {
        Logger.Log("LoadStuffs() executed!");
        ...
        SharedViewModel = ...
    }

The message "LoadStuffs() executed!" only appears at runtime, never in design

The property of the main class :

private SharedViewModel m_sharedViewModel;
public SharedViewModel SharedViewModel
{
    set
    {
        m_sharedViewModel= value;
    }
    get
    {
        Logger.Log("SharedViewModel getter"); <<<<< this is never called as the log.txt is only created at runtime
        if (m_sharedViewModel == null)
        {
            Logger.Log("Initializing DesignSharedViewModel");
            LoadStuffs();  // Initializes m_sharedViewModel
        }
        return m_sharedViewModel;
    }
}

Thanks for your help on this

Share Improve this question edited Feb 21 at 10:22 phil asked Feb 20 at 20:19 philphil 527 bronze badges 8
  • Have you defined the xmlns:local to the CLR namespace which contains your SharedViewModel class? Does that class have a public constructor which takes no parameters? – Soonts Commented Feb 20 at 20:48
  • "The message "LoadStuffs() executed!" only appears at runtime, never in design" - where execatly would you expect a debug message to appear in the designer? – Clemens Commented Feb 21 at 7:26
  • @Soonts , yes it is defined, I updated the question – phil Commented Feb 21 at 8:29
  • @Clemens the message should appear in the console, like in runtime , also my LoadStuffs function works in runtime, additional ui objects are displayed when that function gets called as it sets data in the SharedViewModel. I dont see that in the designer – phil Commented Feb 21 at 8:31
  • There is no debug output from the designer. And the design time DataContext holds a different SharedViewModel instance than that created in OnLoaded. Try creating the additional objects in the view model constructor, maybe in a derived view model class. – Clemens Commented Feb 21 at 8:46
 |  Show 3 more comments

1 Answer 1

Reset to default 0

The cleanest way of allocating a ViewModel to a View at both design-time and run-time is using the ViewModelLocator pattern.

1 - Add a class to handle creation of ViewModels.

public class ViewModelLocator
{
    public ViewModelLocator()
    {
        // include any IOC setup here if required.
    }

    public MainViewModel MainViewModel
    {
        get 
        {
            return new MainViewModel();

            // replace this with a call to the IOC container if any injected servies are required.
        }
   } 

   // repeat for any other ViewModel types required.
}

2 - Create an instance of this locator class in App.xaml, making it a application wide resouce.

<Application.Resources>
    <local:ViewModelLocator x:Key="ViewModelLocator">
</Application.Resources>

3 - in each View, reference this locator instance as a source for its DataContext

<Window
    x:Class="MyApp.MainView"
    ...
    DataContext="{Binding Source={StaticResource ViewModelLocator}, Path=MainViewModel}" />

For a more detailed example including how to have different injected services for design-time and run-time usage, check out my blog post.

本文标签: WPFdDataContexthow to initiate data in design like at runtimeStack Overflow