เหตุใด (Style)Application.Current.Resources[FrameBorder] ไม่อนุญาตให้ฉันเข้าถึงทรัพยากรใน ResourceDirectory ของฉัน

ฉันสร้างทรัพยากรในไฟล์ FrameRes.xaml ดังนี้:

<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms" 
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
                    x:Class="Japanese.Resources.FrameRes">
    <Style x:Key="FrameBorder" TargetType="Frame">
        <Setter Property="CornerRadius" Value="2" />
        <Setter Property="HasShadow" Value="false" />
        <Setter Property="Margin" Value="10,0" />
        <Setter Property="BorderColor" Value="{DynamicResource LineColor}" />
        <Setter Property="Padding" Value="0" />
        <Setter Property="VerticalOptions" Value="Start" />
    </Style>
</ResourceDictionary>

และสิ่งนี้บรรจุอยู่ภายใน:

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:converters="clr-namespace:Japanese" 
             xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="Japanese.App">
    <Application.Resources>
        <ResourceDictionary Source="/Resources/FooterRes.xaml" />
        <ResourceDictionary Source="/Resources/FrameRes.xaml" />
    </Application.Resources>
</Application>

เมื่อฉันพยายามเข้าถึงสิ่งนี้ใน C# เช่นนี้ มันล้มเหลวและบอกว่าไม่มีการอ้างอิงถึง FrameBorder:

var fb2 = (Style)Application.Current.Resources["FrameBorder"];

เมื่อฉันพยายามเข้าถึงสิ่งนี้ใน C # แบบนี้มันก็ใช้งานได้:

Application.Current.Resources.TryGetValue("FrameBorder", out object frameBorder);
var fb = (Style)frameBorder;

ไม่มีใครรู้ว่าทำไมวิธีแรกไม่ทำงาน มันดูเหมือนกันสำหรับฉัน


person Alan2    schedule 24.11.2018    source แหล่งที่มา
comment
ฉันประสบปัญหานี้และโพสต์วิธีแก้ไขที่นี่: stackoverflow.com/a/67992365/6846888   -  person Ângelo Polotto    schedule 15.06.2021


คำตอบ (2)


วิธีที่คุณตั้งค่า คุณมี ResourceDictionary อยู่ใน ResourceDictionary อีกอัน โดยไม่มีคีย์/ชื่อ/ข้อมูลอ้างอิง เมื่อคุณโทร Application.Current.Resources["FrameBorder"]; คุณกำลังเข้าถึงระดับบนสุดของพจนานุกรมและมองหา "FrameBorder" ไม่ใช่ระดับย่อย อย่างไรก็ตาม การเรียก TryGetValue จะต้องผ่านทุกระดับของพจนานุกรม

อ่าน เอกสารเพื่อทำความเข้าใจวิธีเข้าถึงค่าจากพจนานุกรม


ตกลง ฉันได้ลองใช้แท็กและไฟล์ ResourceDictionary แล้ว และฉันก็เห็นว่าคุณผิดตรงไหน

ตาม Xamarin Forms Docs บน ResourceDictionary คุณสามารถเพิ่มไฟล์ ResourceDictionary XAML แบบสแตนด์อโลนลงใน App.xaml ของคุณได้ ดังนี้:

<App ...>
    <App.Resources>

            <!-- Add more resources here -->

            <ResourceDictionary Source="MyResourceDictionary.xaml" />

            <!-- Add more resources here -->

    </App.Resources>
    ...
</App>

คุณสามารถแทนที่ App ด้วย ContentPage หรือ ContentView ขึ้นอยู่กับการใช้งานของคุณ

สิ่งนี้ทำอะไร?

พูดง่ายๆ ก็คือ สิ่งนี้จะสร้างวัตถุ ResourceDictionary ใหม่และรวมไฟล์ ResourceDictionary อื่นๆ เข้าไป มาดูรายละเอียดเพิ่มเติมอีกเล็กน้อย

เริ่มต้นด้วยการดูคุณสมบัติ Application.Current.Resources ซึ่งเป็นประเภท ResourceDictionary และใช้ ICollection, IDictionary และ IResourceDictionary เมื่อพิจารณาถึงอินเทอร์เฟซที่นำไปใช้ คุณสามารถรับค่าด้วย ID ตัวเลขหรือสตริง (เช่น: App.Current.Resources[0] หรือ App.Current.Resources["LabelStyle"]) การดำเนินการนี้จะเข้าถึงเนื้อหา ระดับบนสุด ของพจนานุกรม ดังนั้นเฉพาะเนื้อหาที่สร้างขึ้นในแท็ก <[App/ContentPage/ContentView].Resources> เท่านั้น

คุณยังมีคุณสมบัติที่เรียกว่า MergedDictionaries ซึ่งใช้งาน ICollection ซึ่งหมายความว่าคุณสามารถเข้าถึงรายการได้ด้วยรหัสตัวเลขเท่านั้น (เช่น MyMergedDictionary[0])

เมื่อคุณเพิ่มไฟล์ ResourceDictionary เช่น:

<ResourceDictionary Source="MyResourceDictionary.xaml" />

จริงๆ แล้วคุณกำลัง รวม ไฟล์นี้กับ ResourceDictionary ปัจจุบัน หากต้องการเข้าถึงเนื้อหาของ MyResourceDictionary คุณจะต้องโทร (ใน C#):

App.Current.Resources.MergedDictionaries[0]["InternalKeyName"]

นี่น่าจะอธิบายได้ดีกว่าดังนี้:

<App ...>
    <App.Resources>

            <!-- Called using App.Current.Resources["PrimaryColor"] -->
            <Color x:Key="PrimaryColor">#2196F3</Color>

            <!-- Called using App.Current.Resources.MergedDictionaries[0]["InternalKeyName"] -->
            <ResourceDictionary Source="MyResourceDictionary.xaml" />

    </App.Resources>
    ...
</App>

กรณีของคุณ

ในกรณีของคุณ คุณมีพจนานุกรมสองเล่มที่รวมเข้ากับทรัพยากรแอปพลิเคชันของคุณ: FooterRes และ FrameRes

เพื่อการจัดการที่ดีขึ้น ฉันจะสร้าง enum เช่น:

public enum MergedResourcesEnum
{
    Footer,
    Frame
}

และใช้ enum นี้เมื่อเรียกทรัพยากรใน C# ดังนี้:

Application
    .Current
    .Resources
    .MergedDictionaries[(int)MergedResourcesEnum.Frame]["FrameBorder"];
person Tom    schedule 26.11.2018
comment
ฉันตรวจสอบเอกสารแล้ว แต่ยังไม่แน่ใจว่าจะเข้าถึงค่าจากภายในไฟล์ที่ฉันรวมเข้ากับไดเรกทอรีทรัพยากรได้อย่างไร โปรดทราบว่าเนื่องจากฉันโพสต์คำถาม ฉันได้ลองลบ ResourceDirectory ด้านนอกสุดตามที่คุณแนะนำ แต่ก็ยังใช้งานไม่ได้ - person Alan2; 29.11.2018
comment
ตกลง ฉันได้กระโดดเข้าสู่เอกสาร Xamarin Forms แล้ว และฉันได้แก้ไขคำตอบโดยเพิ่มข้อมูลเพิ่มเติมอีกเล็กน้อย - person Tom; 29.11.2018
comment
นี่ควรเป็นคำตอบที่ยอมรับ ฉันเป็นวิศวกรสนับสนุน MSFT Xamarin - person jgoldberger - MSFT; 01.12.2018

คุณสามารถลองลบแท็ก ResourceDictionary ภายนอกและทั้งสองอย่างได้

var fb2 = (Style)Application.Current.Resources["FrameBorder"];

และ

Application.Current.Resources.TryGetValue("FrameBorder", out object frameBorder);
var fb = (Style)frameBorder;

ทำงานถูกต้อง

ดังนั้นรหัส xaml ของคุณจึงเป็นดังนี้:

(โปรดละเว้นชื่อแพ็คเกจที่ไม่เกี่ยวข้องและ FooterRes.xaml เนื่องจากฉันไม่ได้แชร์ไฟล์ FooterRes.xaml ของคุณ)

<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App75.App">
    <Application.Resources>
        <ResourceDictionary Source="/Resources/FooterRes.xaml" />
    </Application.Resources>
</Application>
person AbbyWang - MSFT    schedule 28.11.2018
comment
ฉันได้ลองทำสิ่งนี้แล้ว แต่ยังไม่พบทรัพยากร - person Alan2; 29.11.2018
comment
@ Alan2 เนื่องจากฉันไม่มีโค้ดเต็ม ฉันเพิ่งสร้างการสาธิตง่ายๆ และมันก็ทำงานได้ดีโดยใช้โซลูชันของฉัน คุณช่วยแบ่งปันโครงการของคุณเพื่อที่ฉันจะได้แก้ไขปัญหานี้ได้ง่ายขึ้น - person AbbyWang - MSFT; 29.11.2018