How to read a resource file within a Portable Class Library?

后端 未结 8 1739
夕颜
夕颜 2020-12-05 03:26

I have a Portable Library which I am using for a Windows Phone application. In that same Portable Library, I have a couple of content files (Build Action = Cont

8条回答
  •  感动是毒
    2020-12-05 03:42

    From http://social.msdn.microsoft.com/Forums/windowsapps/en-US/386eb3b2-e98e-4bbc-985f-fc143db6ee36/read-local-file-in-portable-library#386eb3b2-e98e-4bbc-985f-fc143db6ee36

    File access cannot be done portably between Windows Store apps and Windows Phone 8 apps. You will have to use platform specific code, to open the file and acquire a stream. You can then pass the stream into the PCL.

    If you build it with the Content build action, the XML is not inside of the DLL. It's on the filesystem, and there's no way to get it from inside of the PCL. That is why all of the answers set the build action to Embedded Resource. It places the file inside MyPCL.DLL\Path\To\Content.xml.

    However, if you set the build action to Content and set the copy type to Copy if newer, it will place your files in the same directory as the executable.

    Solution Explorer, Properties, and Windows Explorer

    Therefore, we can just place an interface for reading the file in our PCL. On startup of our nonportable code, we inject an implementation into the PCL.

    namespace TestPCLContent
    {
        public interface IContentProvider
        {
            string LoadContent(string relativePath);
        }
    }
    
    namespace TestPCLContent
    {
        public class TestPCLContent
        {
            private IContentProvider _ContentProvider;
            public IContentProvider ContentProvider
            {
                get
                {
                    return _ContentProvider;
                }
                set
                {
                    _ContentProvider = value;
                }
            }
    
            public string GetContent()
            {
                return _ContentProvider.LoadContent(@"Content\buildcontent.xml");
            }
        }
    }
    

    Now that the PCL is defined above, we can create our interface implementation in nonportable code (below):

    namespace WPFBuildContentTest
    {
        class ContentProviderImplementation : IContentProvider
        {
            private static Assembly _CurrentAssembly;
    
            private Assembly CurrentAssembly
            {
                get
                {
                    if (_CurrentAssembly == null)
                    {
                        _CurrentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
                    }
    
                    return _CurrentAssembly;
                }
            }
    
            public string LoadContent(string relativePath)
            {
                string localXMLUrl = Path.Combine(Path.GetDirectoryName(CurrentAssembly.GetName().CodeBase), relativePath);
                return File.ReadAllText(new Uri(localXMLUrl).LocalPath);
            }
        }
    }
    

    On application startup, we inject the implementation, and demonstrate loading contents.

    namespace WPFBuildContentTest
    {
        //App entrance point. In this case, a WPF Window
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                ContentProviderImplementation cpi = new ContentProviderImplementation();
    
                TestPCLContent.TestPCLContent tpc = new TestPCLContent.TestPCLContent();
                tpc.ContentProvider = cpi; //injection
    
                string content = tpc.GetContent(); //loading
            }
        }
    }
    

    EDIT: I kept it strings instead of Streams for simplicity.

提交回复
热议问题