สตริง WinForms ในไฟล์ทรัพยากร เชื่อมต่อกับตัวออกแบบ

ฉันกำลังพยายามแปลแอป WinForms เป็นหลายภาษา ฉันกำลังพยายามหาวิธีตั้งค่าคุณสมบัติข้อความป้ายกำกับ/ปุ่มของฟอร์มให้อ่านจากไฟล์ทรัพยากรในตัวออกแบบ (แทนที่จะต้องรักษาโค้ดจำนวนมากที่ตั้งค่าโดยทางโปรแกรม)

ฉันพบว่าฉันสามารถตั้งค่า form.Localizable=true ได้ แต่ทรัพยากรต่างๆ จะถูกอ่านจากไฟล์ควบคู่ไปกับแบบฟอร์ม แต่ทรัพยากรของฉันจำนวนมากถูกแชร์ผ่านหลายรูปแบบ

มีวิธีใดในการตั้งค่าข้อความของป้ายกำกับในตัวออกแบบเป็นค่าที่จัดเก็บไว้ในไฟล์ resx ระดับโครงการหรือไม่


person Danny Tuppeny    schedule 03.12.2009    source แหล่งที่มา
comment
ความจำเป็นเบื้องหลังการทำเช่นนี้ในตัวนักออกแบบคืออะไร? ความพยายามในการทำสิ่งนี้ในโค้ดขั้นต่ำ   -  person Walter    schedule 04.12.2009
comment
คุณเคยมีโชคกับเรื่องนี้บ้างไหม? ฉันต้องการสิ่งนี้เช่นกัน ฉันต้องการให้แบบฟอร์มทั้งหมดของฉันเชื่อมโยงกับไฟล์ทรัพยากรไฟล์เดียว   -  person    schedule 09.12.2009
comment
น่าเสียดายที่ไม่ ฉันกำลังเดินสายสิ่งต่าง ๆ มากมายในโค้ด :(   -  person Danny Tuppeny    schedule 11.12.2009
comment
stackoverflow.com/questions/453161/   -  person amir110    schedule 27.10.2019


คำตอบ (5)


เพื่อตอบคำถามไม่มี

แต่ IMO ไม่ควรทำสิ่งนี้หากข้อความเป็นแบบคงที่

อ่านคำตอบของฉันเกี่ยวกับการแปลและทรัพยากร:
ตำแหน่งสตริงทรัพยากร< br> ทำให้แอปพลิเคชัน Windows Forms ที่มีอยู่ทั่วโลก
การใช้ไฟล์ .resx สำหรับข้อความแอปพลิเคชันทั่วโลก

person Jon Seigel    schedule 15.01.2010

ฉันคิดว่าฉันพบวิธีการทำเช่นนี้!

ขั้นแรกใน Resources.resx ของคุณ ให้ตั้งค่า Access Modifier เป็น Public

หลังจากนั้นในโค้ดที่ตัวออกแบบสร้างขึ้น (Form.Designer.cs) คุณสามารถเขียนสิ่งนี้ลงในตัวควบคุมที่เหมาะสม:

this.<control>.Text = Properties.Resources.<stringname>

ตัวอย่างเช่น:

this.footerLabel.Text = Properties.Resources.footerString;

ปล.:ฉันไม่รู้ว่าวิธีนี้มีจริยธรรมแค่ไหน แต่มันได้ผล!

person Isti115    schedule 30.01.2013
comment
นี่คือสิ่งที่ฉันพยายามหลีกเลี่ยง :( แทนที่จะต้องรักษาโค้ดจำนวนมากที่ตั้งค่าไว้โดยทางโปรแกรม - person Danny Tuppeny; 01.02.2013

อย่างไรก็ตาม ง่ายต่อการนำไปใช้ ซึ่งสามารถทำได้กับการควบคุมทุกประเภทที่คุณต้องการเชื่อมโยงกับทรัพยากรหรือคลาสอื่น ๆ ฉันทำสิ่งนี้กับคลาสคงที่ เช่น การตั้งค่าแอปพลิเคชันของฉันเช่นกัน

การป้อนรหัสเช่นนี้:

textBox2.DataBindings.Add("Text", source, "<className>.<PropertyName>");  

ไม่ได้ให้ "ความรู้สึกดีๆ" แก่ฉัน ไม่ต้องสนใจการสะกดคำ

นี่คือตัวอย่างเล็กๆ น้อยๆ ของป้ายกำกับด้านบนที่แสดงรายการแบบเลื่อนลงเกี่ยวกับทรัพยากรของแอปพลิเคชัน

ขั้นแรกตัวควบคุม มีคุณสมบัติใหม่ 1 รายการชื่อ ResourceName ซึ่งเป็นเวทมนตร์ที่มาจากโปรแกรมแก้ไข คุณสมบัตินี้ระบุไว้ในคำอธิบายประกอบเหนือคุณสมบัติ และเรียกว่า ResourceDropDownListPropertyEditor

[Editor(typeof(ResourceDropDownListPropertyEditor), typeof(System.Drawing.Design.UITypeEditor))]

รหัสสำหรับคลาสป้ายกำกับ:

/// <summary>
/// Label bound to resource
/// </summary>
/// <remarks>
/// The bitmap does not appear in the Toolbox for autogenerated controls and components.
/// https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-provide-a-toolbox-bitmap-for-a-control</remarks>
/// <seealso cref="System.Windows.Forms.Label" />
[ToolboxBitmap(typeof(Label))]
public partial class ResourceLabel : Label
{

    /// <summary>
    /// backing field for the resource key property
    /// </summary>
    private string mResourceName;
    [Browsable(true)]
    [DefaultValue("")]
    [SettingsBindable(true)]
    [Editor(typeof(ResourceDropDownListPropertyEditor), typeof(System.Drawing.Design.UITypeEditor))]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Description("Select the resource key that you would like to bind the text to.")]
    public string ResourceName
    {
        get { return mResourceName; }
        set
        {
            mResourceName = value;
            if (!string.IsNullOrEmpty(mResourceName))
            {   
                base.Text = Properties.Resources.ResourceManager.GetString(mResourceName);
            }
        }
    }

    /// <summary>
    /// Designer helper method: https://msdn.microsoft.com/en-us/library/ms973818.aspx
    /// </summary>
    /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
    private bool ShouldSerializeResourceName()
    {
        return !string.IsNullOrEmpty(ResourceName);
    }    
    /// <summary>
    /// Will be default text if no resource is available
    /// </summary>
    [Description("default text if no resource is assigned or key is available in the runtime language")]
    public override string Text
    {
        get { return base.Text; }
        set
        {
            // Set is done by resource name.
        }
    }
}

นี่คือคลาสที่ใช้สำหรับดรอปดาวน์:

/// <summary>
/// used for editor definition on those properties that should be able 
/// to select a resource
/// </summary>
/// <seealso cref="System.Drawing.Design.UITypeEditor" />
class ResourceDropDownListPropertyEditor : UITypeEditor
{
    IWindowsFormsEditorService _service;

    /// <summary>
    /// Gets the editing style of the <see cref="EditValue"/> method.
    /// </summary>
    /// <param name="context">An ITypeDescriptorContext that can be used to gain additional context information.</param>
    /// <returns>Returns the DropDown style, since this editor uses a drop down list.</returns>
    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
        // We're using a drop down style UITypeEditor.
        return UITypeEditorEditStyle.DropDown;
    }

    /// <summary>
    /// Displays a list of available values for the specified component than sets the value.
    /// </summary>
    /// <param name="context">An ITypeDescriptorContext that can be used to gain additional context information.</param>
    /// <param name="provider">A service provider object through which editing services may be obtained.</param>
    /// <param name="value">An instance of the value being edited.</param>
    /// <returns>The new value of the object. If the value of the object hasn't changed, this method should return the same object it was passed.</returns>
    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        if (provider != null)
        {
            // This service is in charge of popping our ListBox.
            _service = ((IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)));

            if (_service != null)
            {


                var items = typeof(Properties.Resources).GetProperties()
                            .Where(p => p.PropertyType == typeof(string))
                            .Select(s => s.Name)
                            .OrderBy(o => o);

                var list = new ListBox();
                list.Click += ListBox_Click;

                foreach (string item in items)
                {
                    list.Items.Add(item);
                }
                if (value != null)
                {
                    list.SelectedValue = value;
                }

                // Drop the list control.
                _service.DropDownControl(list);

                if (list.SelectedItem != null && list.SelectedIndices.Count == 1)
                {
                    list.SelectedItem = list.SelectedItem.ToString();
                    value = list.SelectedItem.ToString();
                }

                list.Click -= ListBox_Click;
            }
        }

        return value;
    }

    private void ListBox_Click(object sender, System.EventArgs e)
    {
        if (_service != null)
            _service.CloseDropDown();


    }
}

ในที่สุดสิ่งที่คุณได้รับจะมีลักษณะเช่นนี้ในขณะออกแบบ: มุมมองเวลาออกแบบ

ชื่อทรัพยากรจะถูกสร้างขึ้นเมื่อคุณทิ้งการควบคุมบนแบบฟอร์มของคุณ โดยจะไม่เห็นการเปลี่ยนแปลงจนกว่าคุณจะคอมไพล์ใหม่และปิด/เปิดแบบฟอร์ม หรือปล่อยป้ายกำกับใหม่บนแบบฟอร์ม

person Walter Vehoeven    schedule 30.04.2018
comment
เพื่อให้เป็นโซลูชันที่สมบูรณ์ ควรเพิ่มคุณสมบัติพิเศษบนป้ายกำกับที่อนุญาตให้เชื่อมโยงกับ ประเภท ทรัพยากรเฉพาะ จากนั้นจึงอนุญาตให้ใช้สตริงจากประเภทนั้นได้ ตามที่เป็นอยู่ ขณะนี้คุณต้องกำหนดประเภท Properties.Resources นอกจากนี้ยังมีข้อ จำกัด มากเนื่องจากคุณต้องกำหนดคุณสมบัติใหม่ (หรือสอง) ใหม่สำหรับแต่ละคุณสมบัติการควบคุมที่คุณต้องการผูกกับ... - person Ian Kemp; 21.09.2020

วิธีเดียวที่ฉันคิดได้คือการสร้างการควบคุมแบบกำหนดเองที่จะเพิ่มคุณสมบัติสำหรับชื่อทรัพยากร เมื่อตั้งค่าคุณสมบัติแล้ว ให้ดึงค่าจากไฟล์ทรัพยากรโปรเจ็กต์แล้วตั้งค่าคุณสมบัติข้อความด้วย คุณจะต้องแน่ใจว่าข้อความไม่ได้รับการซีเรียลไลซ์ ไม่เช่นนั้นอาจเขียนทับค่าที่กำหนดโดย ResourceName

public class ResourceLabel
    : Label
{
    private string mResourceName;
    public string ResourceName
    {
        get { return mResourceName; }
        set
        {
            mResourceName = value;
            if (!string.IsNullOrEmpty(mResourceName))
                base.Text = Properties.Resources.ResourceManager.GetString(mResourceName);
        }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public override string Text
    {
        get { return base.Text; }
        set 
        { 
            // Set is done by resource name.
        }
    }
}
person Brian    schedule 04.12.2009
comment
ฉันคิดถึงสิ่งที่คล้ายกัน แต่ดูเหมือนว่าจะน่ารังเกียจมากกว่าการมีหนึ่ง resx ต่อไฟล์หรือตั้งค่าเป็นโค้ด ฉันรู้สึกผิดหวังที่ดูเหมือนจะไม่มีวิธีในตัวในการทำเช่นนี้ ดูเหมือนว่าจะเป็นเพียงการปรับแต่งเล็กน้อยจากสิ่งที่มีอยู่ในคุณสมบัติ Localizable เพียงแต่ว่ามันต้องการคุณสมบัติไฟล์ Resx ด้วยเช่นกัน :( - person Danny Tuppeny; 04.12.2009

ฉันเพิ่งดูสิ่งนี้มาจริงๆ
หากคุณเป็นเจ้าของการควบคุม เช่น เป็นการควบคุมที่คุณกำหนดเอง คุณสามารถใช้ CodeDOM

อ่าน บทความนี้เป็นข้อมูลพื้นฐานบางส่วนและดาวน์โหลดตัวอย่างนี้เพื่อดูวิธีการทำงาน .

ในแอปของเรา เราจำเป็นต้องแทนที่ตัวยึดตำแหน่งด้วย "DisplayText" เพื่อสร้างฐานข้อมูล
ดังนั้นเราจึงมีคุณสมบัติข้อความ เช่น "Order {Product}" และเราต้องการแทนที่ด้วย GetDisplayText("Order {Product}")`

ดังนั้นเพื่อที่จะทำสิ่งนี้ ฉันได้เพิ่มโค้ดต่อไปนี้:

                statements.OfType<CodeAssignStatement>()
                    .Where(s => s.Left is CodePropertyReferenceExpression && ((CodePropertyReferenceExpression)s.Left).PropertyName == "Text")
                    .ToList().ForEach(s =>
                    {
                        s.Right = new CodeMethodInvokeExpression(
                            new CodeMethodReferenceExpression(new CodeTypeReferenceExpression("Core.DisplayText"), "GetDisplayText"),
                            s.Right);
                    });

อย่างไรก็ตาม ฉันยังคงทดลองมันอยู่และฉันยังไม่ได้สร้างวิธีแก้ปัญหาที่ใช้งานได้... แต่มันอาจช่วยคุณได้

:-)

person Luke T O'Brien    schedule 07.02.2019