locked
Why is #if WINDOWS_PHONE_APP directive not working?...

    Question

  • IDE: VS Express 2013 for Windows
    Project
    : Universal
    IoC: MEF
    Target OS: 8.1

    Hi,

    In testing on my Windows Phone App on my Device the #if WINDOWS_PHONE_APP directive is not working in my ViewModel, keep in mind I'm using MEF to inject my ViewModels into the DataContext of the my Page's.

    MEF Injection:

    [Export(typeof(HubPage))]
    public sealed partial class HubPage : VisualStateAwarePage
    {
    	public HubPage()
    	{
    		this.InitializeComponent();
    		Debug.WriteLine("HubPage InitializeComponent");
    	}
    
    	[Import]
    	public NathsarTS.UILogic.Interfaces.IHubPageViewModel ViewModel
    	{
    		set
    		{
    			this.DataContext = value;
    		}
    		get
    		{
    			return DataContext as NathsarTS.UILogic.Interfaces.IHubPageViewModel;
    		}
    	}
    
    	/// <summary>
    	/// Called when a part's imports have been satisfied and it is safe to use.
    	/// </summary>
    	[OnImportsSatisfied]
    	public void OnImportsSatisfied()
    	{
    		// IPartImportsSatisfiedNotification is useful when you want to coordinate doing some work
    		// with imported parts independent of when the UI is visible.
    		Debug.WriteLine("HubPage OnImportsSatisfied instantiation");
    
    		this.ViewModel.ObserverHubPageLoadedEventArgs =
    			Observable.FromEventPattern<object, RoutedEventArgs>(this.pageRoot, "Loaded");
    		this.ViewModel.DisposableHubPageLoadedEvent =
    			this.ViewModel.ObserverHubPageLoadedEventArgs.Subscribe(evt => this.ViewModel.OnPageRootHubPageLoadedEvent(evt.Sender, evt.EventArgs));
    
    		//NathsarTS.UILogic.Interfaces.IObservableService ObservableService = ServiceLocator.Current.GetInstance<NathsarTS.UILogic.Interfaces.IObservableService>();
    		//this.ViewModel.NavigationHelper = new NathsarTS.Common.Logic.NavigationHelper(this);
    		//this.ViewModel.NavigationHelper.LoadState += this.ViewModel.NavigationHelperLoadState;
    	}
    }

    My App:

            public App()
            {
    #if WINDOWS_PHONE_APP
                Debug.WriteLine("directive WINDOWS_PHONE_APP is defined...");
    #elif WINDOWS_APP
                Debug.WriteLine("directive WINDOWS_APP is defined...");
    #else
                Debug.WriteLine("Error directive WINDOWS_PHONE_APP/WINDOWS_APP not defined...");
    #endif
                this.InitializeComponent();
                this.RequestedTheme = ApplicationTheme.Light;
            }

    Results: directive WINDOWS_PHONE_APP is defined...

    In My ViewModel:

            public async void OnPageRootHubPageLoadedEvent(object sender, RoutedEventArgs args)
            {
                Debug.WriteLine("OnPageRootHubPageLoadedEvent instantiation");
    
    #if WINDOWS_PHONE_APP
                Debug.WriteLine("OnPageRootHubPageLoadedEvent (Phone) instantiation");
    
                var sampleDataGroups = await SampleDataSource.GetGroupsAsync();
                this.DefaultDataModel["Groups"] = sampleDataGroups;
    #elif WINDOWS_APP
                Debug.WriteLine("OnPageRootHubPageLoadedEvent (Windows) instantiation");
    
                var sampleDataGroup = await NathsarTS.Common.DataModel.SampleDataSource.GetGroupAsync("Group-4");
                this.DefaultDataModel["Section3Items"] = sampleDataGroup;
    #else
                Debug.WriteLine("Error directive WINDOWS_PHONE_APP/WINDOWS_APP not defined...");
                await Task.FromResult<object>(null);
    #endif
            }


    Results: Error directive WINDOWS_PHONE_APP/WINDOWS_APP not defined...

    Its defined in the Phone Project Properties "Conditional compilation symbols:" as NETFX_CORE;WINDOWS_PHONE_APP.  Seeing this doesn't work, how can I get check if I'm in Windows or Phone to make this work?  I don't want to create two different ViewModels for every Page.

    I'm assuming because its part of the Page's DataContext?


    Code is like a box of chocolates!...


    • Edited by VcDeveloper Friday, September 19, 2014 5:48 PM Maybe the reason comment
    Friday, September 19, 2014 7:07 AM

Answers

  • The only way to get around this problem was to create a Boolean Property and set it during my OnImportsSatisfied() by MEF.

            /// <summary>
            /// Called when a part's imports have been satisfied and it is safe to use.
            /// </summary>
            [OnImportsSatisfied]
            public void OnImportsSatisfied()
            {
                // IPartImportsSatisfiedNotification is useful when you want to coordinate doing some work
                // with imported parts independent of when the UI is visible.
                Debug.WriteLine("HubPage OnImportsSatisfied instantiation");
    
    #if WINDOWS_PHONE_APP
                Debug.WriteLine("directive WINDOWS_PHONE_APP is defined...");
                this.ViewModel.Windows_Phone_App = true;
    #elif WINDOWS_APP
                Debug.WriteLine("directive WINDOWS_APP is defined...");
                this.ViewModel.Windows_Phone_App = false;
    #else
                Debug.WriteLine("Error directive WINDOWS_PHONE_APP/WINDOWS_APP not defined...");
    #endif
            }

    And in my ViewModel:

            private Boolean windows_Phone_App;
            public Boolean Windows_Phone_App
            {
                get { return this.windows_Phone_App; }
                set { SetProperty(ref this.windows_Phone_App, value); }
            }

    So for now I'll just mark this as answered....


    Code is like a box of chocolates!...


    • Marked as answer by VcDeveloper Sunday, September 21, 2014 3:17 AM
    • Edited by VcDeveloper Sunday, September 21, 2014 3:17 AM
    Sunday, September 21, 2014 3:17 AM

All replies

  • These are compile-time constants so their presence has to do with when they are compiled. Runtime concepts such as DataContext aren't relevant.

    It's not clear from your description which project this code is in, but check that it is being built with the symbols defined that you expect.

    If you need help tracking this down please share a minimal project demonstrating the problem on your OneDrive.

    --Rob

    Saturday, September 20, 2014 12:29 AM
    Owner
  • Hi Rob, thanks for the reply! 

    The HubPage.xaml.cs (above) is the same for both projects, both are sharing HubPageViewModel, this is the purpose for using the #if directives, so I don't have to create two different ViewModels for each project.  They both will be using the same code, except for some cases where a different data key is needed like in the example (code block 3).

    I'm guessing because of the injection the compile directive will not be in effect in the ViewModel, so I will need the define the directive in the ViewModel.  Then it looks like I would have to create and set a property in the ViewModel during the instantiation of the HubPage.xaml.cs, because the directive isn't present.

    Code is like a box of chocolates!...

    Saturday, September 20, 2014 1:09 AM
  • It sounds like you're still mixing up runtime and compile time issues, but you haven't given enough information to diagnose the problem.

    If you need help tracking this down please share a minimal project demonstrating the problem on your OneDrive.

    Saturday, September 20, 2014 4:51 AM
    Owner
  • The problem is simple as posted above, when you create a Universal Project it includes an directive automatically in the App class for the Phone Project:

    #if WINDOWS_PHONE_APP
            private TransitionCollection transitions;
    #endif
    

    which means this directive should be available for checking anywhere in additional code.  For some reason its not available when I inject the ViewModel into a Page class, as define above (code block 1).  Even in the MainPage that is created automatically has this:

    #if WINDOWS_PHONE_APP
                this.NavigationCacheMode = NavigationCacheMode.Required;
    #endif
    

    But, when I inject a ViewModel into the MainPage as define above (code block 1) the directive is not available.  Even after the injection I still can't test for the directive in the ViewModel.  Now, when I checked for the directive in code-behind its available.

            private void Hub_SectionHeaderClick(object sender, HubSectionHeaderClickEventArgs e)
            {
                Debug.WriteLine("Hub_SectionHeaderClick : " + e.Section.Header.ToString());
    
    #if WINDOWS_PHONE_APP
                Debug.WriteLine("directive WINDOWS_PHONE_APP is defined...");
    #elif WINDOWS_APP
                Debug.WriteLine("directive WINDOWS_APP is defined...");
    #else
                Debug.WriteLine("Error directive WINDOWS_PHONE_APP/WINDOWS_APP not defined...");
    #endif
            }
    

    This is the code-behind  for the HubPage.xaml.cs for the Windows Project.  This tells me its there, so I should be able to use it anywhere in code except for the injected ViewModel.


    Code is like a box of chocolates!...

    Sunday, September 21, 2014 2:52 AM
  • The only way to get around this problem was to create a Boolean Property and set it during my OnImportsSatisfied() by MEF.

            /// <summary>
            /// Called when a part's imports have been satisfied and it is safe to use.
            /// </summary>
            [OnImportsSatisfied]
            public void OnImportsSatisfied()
            {
                // IPartImportsSatisfiedNotification is useful when you want to coordinate doing some work
                // with imported parts independent of when the UI is visible.
                Debug.WriteLine("HubPage OnImportsSatisfied instantiation");
    
    #if WINDOWS_PHONE_APP
                Debug.WriteLine("directive WINDOWS_PHONE_APP is defined...");
                this.ViewModel.Windows_Phone_App = true;
    #elif WINDOWS_APP
                Debug.WriteLine("directive WINDOWS_APP is defined...");
                this.ViewModel.Windows_Phone_App = false;
    #else
                Debug.WriteLine("Error directive WINDOWS_PHONE_APP/WINDOWS_APP not defined...");
    #endif
            }

    And in my ViewModel:

            private Boolean windows_Phone_App;
            public Boolean Windows_Phone_App
            {
                get { return this.windows_Phone_App; }
                set { SetProperty(ref this.windows_Phone_App, value); }
            }

    So for now I'll just mark this as answered....


    Code is like a box of chocolates!...


    • Marked as answer by VcDeveloper Sunday, September 21, 2014 3:17 AM
    • Edited by VcDeveloper Sunday, September 21, 2014 3:17 AM
    Sunday, September 21, 2014 3:17 AM