لن يتم تحميل إنشاء CroppedBitmap في وقت التشغيل من المورد

StackOverflow https://stackoverflow.com/questions/1056021

سؤال

أحاول كتابة تعليمات برمجية لتحميل صورة من أحد الموارد، ثم قصها.يعمل هذا الرمز عندما أقوم به كله أو جزء منه في XAML.أريد التبديل من XAML الكامل إلى الكود الكامل، حتى أتمكن من إعادة استخدام هذا في أكثر من مكان، مع Uris مختلف.

ولكن عندما أحاول القيام بنفس الشيء في التعليمات البرمجية، أحصل على DirectoryNotFoundException، لأنه فجأة يبدأ في محاولة البحث عن مجلد على القرص، بدلاً من تحميل الصورة من المورد.

  • إذا قمت بتحميل BitmapImage في XAML، ثم قمت بإنشاء CroppedBitmap في XAML، فسيعمل كل شيء.
  • إذا قمت بتحميل BitmapImage في XAML، ثم قمت بكتابة التعليمات البرمجية لإنشاء CroppedBitmap منه، فسيعمل كل شيء.
  • إذا قمت بتحميل الصورة النقطية في التعليمات البرمجية، بدون إنشاء CroppedBitmap منه، كل شيء يعمل.
  • ولكن إذا قمت بتحميل BitmapImage في الكود و إنشاء CroppedBitmap في التعليمات البرمجية، ويحاول التحميل من نظام الملفات بدلاً من الموارد، وأحصل على DirectoryNotFoundException.

نماذج التعليمات البرمجية أدناه.أنا متأكد من أنني أفعل شيئًا غبيًا، لكنني قمت بتنفيذ الأمر برمته ثلاث مرات الآن (مرة في تطبيقي الحقيقي، ومرة ​​في تطبيق اختباري، ومرة ​​أثناء كتابة هذا السؤال)، وحصلت على نفس الشيء النتائج ثلاث مرات.

بالنسبة لجميع نماذج التعليمات البرمجية التالية، قمت بإنشاء مجلد صور داخل مشروعي، وأضفت صورة موجودة هناك تسمى "elf.png"، مع تعيين الخصائص على الإعدادات الافتراضية (Build Action = "Resource"؛نسخ إلى دليل الإخراج = "لا تنسخ").


حالة 1:كل من BitmapImage وCroppedBitmap في XAML.

<Window x:Class="WpfApplication8.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <BitmapImage x:Key="fullImage" UriSource="Images/elf.png"/>
        <CroppedBitmap x:Key="croppedImage" Source="{StaticResource fullImage}"
                       SourceRect="0 0 240 320"/>
    </Window.Resources>
    <Image Source="{StaticResource croppedImage}"/>
</Window>

يُظهر هذا الجزء الذي تم اقتصاصه من الصورة النقطية، كما هو متوقع.


الحالة 2:صورة نقطية في XAML؛CroppedBitmap في الكود الخلفي.

XAML:

<Window x:Class="WpfApplication8.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <BitmapImage x:Key="fullImage" UriSource="Images/elf.png"/>
    </Window.Resources>
    <Image Name="image"/>
</Window>

المنشئ في الكود الخلفي:

public Window1()
{
    InitializeComponent();
    var fullImage = (BitmapImage) FindResource("fullImage");
    var croppedImage =
        new CroppedBitmap(fullImage, new Int32Rect(0, 0, 240, 320));
    image.Source = croppedImage;
}

يُظهر هذا أيضًا الجزء الذي تم اقتصاصه من الصورة النقطية، كما هو متوقع.


الحالة 3:الصورة النقطية في الكود؛لا توجد خريطة نقطية مقصوصة.

public Window1()
{
    InitializeComponent();
    var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
    var fullImage = new BitmapImage(uri);
    image.Source = fullImage;
}

يُظهر هذا الصورة النقطية بأكملها.ليس هذا ما أريده، لكنه يخبرني أنني أعرف كيفية كتابة كود C# لإنشاء النوع الصحيح من Uri وتحميل صورة نقطية من أحد الموارد.


الحالة 4:BitmapImage وCroppedBitmap في التعليمات البرمجية.

    public Window1()
    {
        InitializeComponent();
        var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
        var fullImage = new BitmapImage(uri);
        var croppedImage =
            new CroppedBitmap(fullImage, new Int32Rect(0, 0, 240, 320));
        image.Source = croppedImage;
    }

بقدر ما أستطيع أن أقول، هذا فقط يجمع نفس القطع كما كان من قبل.فهو يستخدم تعليمات برمجية أعرف أنها ستقوم بتحميل صورة نقطية من أحد الموارد، وتعليمات برمجية أعرف أنها ستقوم باقتصاص قسم من صورة نقطية تم تحميلها.ولكن بطريقة ما، عندما يتم تجميع الاثنين معًا، ينسى أن المورد موجود، ويحاول التحميل من القرص.أحصل على الاستثناء التالي:

  • استثناء XamlParse:"لا يمكن إنشاء مثيل لـ 'Window1' المحدد في التجميع 'WpfApplication8، الإصدار=1.0.0.0، الثقافة=محايدة، PublicKeyToken=null'.تم طرح الاستثناء بواسطة هدف الاستدعاء.خطأ في ملف العلامات 'Window1.xaml' السطر 1 الموضع 13."
    • الاستثناء الداخلي: استثناء الهدف:"تم طرح استثناء من خلال هدف الاحتجاج."
      • الاستثناء الداخلي: DirectoryNotFoundException:"تعذر العثور على جزء من المسار 'C:\svn\WpfApplication8\WpfApplication8\bin\Debug\Images\elf.png'."

يُظهر تتبع مكدس الاستثناء الداخلي الداخلي أن الاستثناء الأصلي (DirectoryNotFoundException) قد تم طرحه بواسطة السطر الذي يقوم بإنشاء نسخة CroppedBitmap.لا أعرف لماذا يحاول هذا السطر القراءة من القرص، أو لماذا لا يعمل عندما يعمل XAML المعادل بقدر ما أستطيع أن أقول بشكل جيد.

نظرًا لأنني أعرف أن XAML يستخدم مُنشئات بدون معلمات، فقد جربت أيضًا الإصدار التالي، والذي يجب أن يكون أقرب كثيرًا إلى ما يفعله XAML فعليًا:

public Window1()
{
    InitializeComponent();
    var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
    var fullImage = new BitmapImage();
    fullImage.BeginInit();
    fullImage.UriSource = uri;
    fullImage.EndInit();
    var croppedImage = new CroppedBitmap();
    croppedImage.BeginInit();
    croppedImage.Source = fullImage;
    croppedImage.SourceRect = new Int32Rect(0, 0, 240, 320);
    croppedImage.EndInit();
    image.Source = croppedImage;
}

نفس الاستثناء، هذه المرة من croppedImage.EndInit(); خط.

هل لديك أي أفكار حول كيفية الحصول على إصدار كامل التعليمات البرمجية لتحميل المورد بشكل صحيح واقتصاص الصورة؟ما الذي يحدث في إصدار XAML المختلف؟

هل كانت مفيدة؟

المحلول

تبين أن السحر موجود في BitmapImage's BaseUri ملكية.يبدو أن BaseUri يعمل بمثابة "الدليل الحالي" الذي يرتبط به UriSource.

عندما تم تحميل صورة BitmapImage الخاصة بي من XAML، تم تعيين BaseUri بطريقة سحرية على "pack://application:,,,/WpfApplication8;component/window1.xaml".عندما قمت بتعديل مقتطف التعليمات البرمجية رقم 4 لتعيين fullImage.BaseUri بشكل صريح على نفس القيمة قبل إنشاء CroppedBitmap، نجح كل شيء.

لماذا عملت من XAML (ومن فقط-BitmapImage-without-CroppedBitmap)

إذن من أين أتت قيمة BaseUri السحرية هذه؟

BaseUri هو جزء من IUriContext واجهه المستخدم.تم تعيين IUriContext.BaseUri في مكانين في تجميعات WPF، وبين الأمثلة المختلفة، تمكنت من الوصول إلى كلاهما منهم.لا عجب أنني كنت في حيرة من أمري.

  • BamlRecordReader.ElementInitialize. يقوم محمل BAML تلقائيًا بتعيين BaseUri في أي وقت يقوم فيه بتحميل عنصر يقوم بتنفيذ IUriContext.وهذا ما يفسر سبب نجاح المثالين رقم 1 ورقم 2:تم تحميلها من مورد BAML المجمع.
  • Image.UpdateBaseUri (يتم استدعاؤه كلما تم تغيير خاصية المصدر).يتحقق هذا لمعرفة ما إذا كان المصدر يطبق IUriContext، وإذا كان الأمر كذلك، يقوم بتعيين BaseUri الخاص به.وهذا ما يفسر سبب نجاح مثالي رقم 3:أدى دفع الصورة النقطية إلى واجهة المستخدم الرسومية إلى إجبارها على الحصول على مسار البحث الصحيح.

فهو يبحث فقط عن الصورة الموجودة في موارد EXE عندما يتم تعيين BaseUri على الحزمة السحرية:// URI.وبدون ذلك (كما يحدث عندما يتم إنشاء كل شيء في التعليمات البرمجية ولا يتم دفعه إلى واجهة المستخدم الرسومية)، فإنه يظهر فقط على القرص.

المأزق

كما هو مذكور أعلاه، يمكنني تشفير BaseUri بشكل ثابت.لكن ال BaseUriHelper يوفر الفصل حلاً أفضل:

fullImage.BaseUri = BaseUriHelper.GetBaseUri(this);

يؤدي هذا إلى تعيين الصورة الكاملة بحيث تحتوي على نفس BaseUri مثل النافذة (this).إذا تم ذلك قبل إنشاء CroppedBitmap، فسيعمل كل شيء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top