Как я могу иметь поле класса быть typeOf двух разных классов в соответствии с настройкой в ​​конфигурации? - PullRequest
0 голосов
/ 08 ноября 2019

Я использую сообщество Visual Studio 2017. В форме пользовательского интерфейса проекта System.Windows.Forms.WebBrowser используется для предварительного просмотра PDF-документа. Мне было поручено добавить возможность предварительного просмотра указанного документа также с помощью Chrome, а не только Explorer.

Для этого я установил пакет NuGet CefSharp.WinForms и использовал класс ChromiumWebBrowser. Проблема заключается в том, что в исходном виде поле PDFPreview объявляется как веб-браузер и на него ссылаются около 20 раз. Кроме того, классы WebBrowser и ChromiumWebBrowser очень похожи, но не каждый метод или поле называются одним и тем же именем / способом или имеют соответствующий аналог.

Я думал, что решение может включать использование обобщений или интерфейсов, но сейчас ятолько что создал новый класс Browser, который создает экземпляр и использует либо поле WebBrowser, либо ChromiumWebBrowser в соответствии с логическим значением, переданным в конструкторе, и для каждого метода, который мне нужно использовать, из перечисленных выше классов я переопределил его внутри Browser, используя их исходные методы, в соответствии с тем, какой объект IЯ работаю над тем, как если бы я переопределял методы обоих классов (к сожалению, я знаю, что не могу заставить браузер расширять несколько классов, и я не могу создать интерфейс, реализованный WebBrowser и ChromiumWebBrowser, так как те не могут менялись).

Извините, если я объясняю это очень грязно или неправильно использую термины, я все еще учусь кодировать, но, надеюсь, сам код прояснит ситуацию.

Это ориginal WebBrowser field и все используемые методы / поля:

WebBrowser PDFPreview = null;
PDFPreview.IsDisposed
PDFPreview.Url == new UriBuilder(documentFilePath).Uri
PDFPreview = new WebBrowser();
scannerOperationContainer.Panel2.Controls.Add(PDFPreview);
PDFPreview.Dock = DockStyle.Fill;
PDFPreview.Navigate(documentFilePath);
PDFPreview.Document.Body.Style = "zoom:50%";
PDFPreview.Hide();
PDFPreview.Stop();
PDFPreview.Dispose();

Вот класс Browser, который я создал как «cointaner» для WebBrowser и ChromiumWebBrowser:

class Browser
    {
        public bool useChrome;
        public WebBrowser explorerBrowser = null;
        public ChromiumWebBrowser chromeBrowser = null;

        public bool isDisposed
        {
            get{return IsDisposed();}
        }

        public Uri url
        {
            get {return Url();}
        }

        public DockStyle dock
        {
            get { return Dock(); }
            set
            {
                if (useChrome)
                { chromeBrowser.Dock = value; }
                else
                { explorerBrowser.Dock = value; }
            }
        }

        public HtmlDocument document
        {
            get { return Document(); }
        }

        public static explicit operator WebBrowser(Browser b) => b.explorerBrowser;
        public static explicit operator ChromiumWebBrowser(Browser b) => b.chromeBrowser;

        public Browser(bool useChrome)
        {
            if (useChrome)
            {
                //chromeBrowser = new ChromiumWebBrowser("https://www.google.com/");
                //Since Load doesn't seem to work I create the chromeBrowser directly when I would need to load
                //to a new URL, it's bad but for how it's written the code in the parent form it's making it work
                this.useChrome = useChrome;
            }
            else
            {
                explorerBrowser = new WebBrowser();
                this.useChrome = useChrome;
            }
        }

        public void Navigate(string urlString)
        {
            if (useChrome)
            {
                chromeBrowser = new ChromiumWebBrowser(urlString);
            }
            else
            {
                explorerBrowser.Navigate(urlString);
            }
        }

        public void Hide()
        {
            if (useChrome)
            {
                chromeBrowser.Hide();
            }
            else
            {
                explorerBrowser.Hide();
            }
        }

        public void Stop()
        {
            if (useChrome)
            {
                chromeBrowser.Stop();
            }
            else
            {
                explorerBrowser.Stop();
            }
        }

        public void Dispose()
        {
            if (useChrome)
            {
                chromeBrowser.Dispose();
            }
            else
            {
                explorerBrowser.Dispose();
            }
        }
        //***
        //GETTERS AND SETTERS
        //***
        public bool IsDisposed()
        {
            if (useChrome)
            {
                return chromeBrowser.IsDisposed;
            }
            else
            {
                return explorerBrowser.IsDisposed;
            }
        }

        public Uri Url()
        {
            if (useChrome)
            {
                return new UriBuilder(chromeBrowser.Address).Uri;
            }
            else
            {
                return explorerBrowser.Url;
            }
        }
        public DockStyle Dock()
        {
            if (useChrome)
            {
                return chromeBrowser.Dock;
            }
            else
            {
                return explorerBrowser.Dock;
            }
        }
        public HtmlDocument Document()
        {
            if (useChrome)
            {
                return null; //Will never get here, see form1
            }
            else
            {
                return explorerBrowser.Document;
            }
        }
    } 

Я хотел изменитьсформировать исходный код как можно меньше, но мне пришлось изменить несколько битов, чтобы он работал:

Мне нужно вызвать Navigate () сразу после его создания, а также есть проверка if, если необходимо привести к WebBrowserили ChromiumWebBrowser по адресу scannerOperationContainer.Panel2.Controls.Add (PDFPreview).

Хотя основное и, я надеюсь, единственное изменение, которое я хотел бы иметь, было бы следующим:

Browser PDFPreview = null;
PDFPreview = new Browser(ConfigurationDocument.GetBooleanProperty("EnableChromePdfViewer"));

Этот код работает какна данный момент, но я подозреваю, что это очень уродливо и плохо продумано.

Мне было интересно, должен ли быть более умный / более элегантный / правильный способ решения этой проблемы. Я подумал, что, возможно, Browser может быть универсальным классом и каким-то образом передать из config.xml правильный тип класса? Хотя я не знаю, как это написать. Или, может быть, создать два класса, которые расширяют WebBrowser и ChromiumWebBrowser, а затем имеют интерфейс, реализованный обоими? Или правильная форма в другом направлении полностью?

...