อะไรคือความแตกต่างระหว่างคุณสมบัติการพึ่งพา (กำหนดเอง) และคุณสมบัติที่แนบมาใน WPF? แต่ละอย่างใช้อะไรบ้าง? การใช้งานโดยทั่วไปแตกต่างกันอย่างไร?
อะไรคือความแตกต่างระหว่างคุณสมบัติการพึ่งพา (กำหนดเอง) และคุณสมบัติที่แนบมาใน WPF? แต่ละอย่างใช้อะไรบ้าง? การใช้งานโดยทั่วไปแตกต่างกันอย่างไร?
คำตอบ:
เนื่องจากฉันพบเอกสารเกี่ยวกับเรื่องนี้เพียงเล็กน้อยหรือไม่มีเลยจึงต้องใช้ซอร์สโค้ดแต่นี่คือคำตอบ
มีความแตกต่างระหว่างการลงทะเบียนคุณสมบัติอ้างอิงเป็นคุณสมบัติปกติและเป็นคุณสมบัติที่แนบมานอกเหนือจากคุณสมบัติ "เชิงปรัชญา" ( คุณสมบัติปกติมีวัตถุประสงค์เพื่อใช้โดยประเภทการประกาศและประเภทที่ได้รับคุณสมบัติที่แนบมามีวัตถุประสงค์เพื่อใช้เป็น ส่วนขยายบน DependencyObject
อินสแตนซ์โดยพลการ ) "Philosophical" เนื่องจากตามที่ @MarqueIV สังเกตเห็นในความคิดเห็นของเขาต่อคำตอบของ @ ReedCopsey คุณสมบัติทั่วไปยังสามารถใช้กับDependencyObject
อินสแตนซ์ตามอำเภอใจได้
ยิ่งไปกว่านั้นฉันต้องไม่เห็นด้วยกับคำตอบอื่น ๆ ที่ระบุว่าคุณสมบัติที่แนบมานั้นเป็น "ประเภทของคุณสมบัติการพึ่งพา" เพราะมันทำให้เข้าใจผิด - ไม่มีคุณสมบัติการพึ่งพา "ประเภท" ใด ๆ เฟรมเวิร์กไม่สนใจว่าคุณสมบัตินั้นได้รับการลงทะเบียนตามที่แนบมาหรือไม่ - ยังไม่สามารถระบุได้ด้วยซ้ำ (ในแง่ที่ว่าข้อมูลนี้ไม่ได้รับการบันทึกเนื่องจากไม่เกี่ยวข้อง) ในความเป็นจริงคุณสมบัติทั้งหมดได้รับการลงทะเบียนราวกับว่าเป็นคุณสมบัติที่แนบมา แต่ในกรณีปกติมีการดำเนินการเพิ่มเติมบางอย่างที่ปรับเปลี่ยนพฤติกรรมเล็กน้อย
เพื่อให้คุณไม่ต้องกังวลกับการใช้ซอร์สโค้ดด้วยตัวเองนี่คือสิ่งที่เกิดขึ้น
เมื่อลงทะเบียนคุณสมบัติโดยไม่ระบุข้อมูลเมตาให้เรียก
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
ให้ผลลัพธ์เหมือนกับการโทร
DependencyProperty.RegisterAttached(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
อย่างไรก็ตามเมื่อระบุข้อมูลเมตาการโทร
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass),
typeMetadata: new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceCallback,
DefaultValue = "default value",
PropertyChangedCallback = ChangedCallback
});
เทียบเท่ากับการโทร
var property = DependencyProperty.RegisterAttached(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass),
defaultMetadata: new PropertyMetadata
{
DefaultValue = "default value",
});
property.OverrideMetadata(
forType: typeof(MyClass),
typeMetadata: new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceCallback,
DefaultValue = "default value",
PropertyChangedCallback = ChangedCallback
});
ความแตกต่างของคีย์ (และเท่านั้น) ระหว่างคุณสมบัติการพึ่งพาปกติและที่แนบมาคือข้อมูลเมตาเริ่มต้นที่พร้อมใช้งานผ่านคุณสมบัติDependencyProperty.DefaultMetadata สิ่งนี้ยังกล่าวถึงในส่วนหมายเหตุ :
สำหรับคุณสมบัติที่ไม่มีการระบุประเภทข้อมูลเมตาที่ส่งคืนโดยคุณสมบัตินี้ไม่สามารถแคสต์ไปยังชนิดPropertyMetadata ที่สืบทอดมาได้แม้ว่าคุณสมบัติจะถูกลงทะเบียนด้วยชนิดข้อมูลเมตาที่ได้รับ หากคุณต้องการให้ข้อมูลเมตาที่ลงทะเบียนเดิมรวมถึงประเภทข้อมูลเมตาที่ได้รับดั้งเดิมให้เรียกGetMetadata (Type)แทนโดยส่งประเภทการลงทะเบียนเดิมเป็นพารามิเตอร์
สำหรับคุณสมบัติที่แนบมาประเภทของข้อมูลเมตาที่ส่งคืนโดยคุณสมบัตินี้จะตรงกับประเภทที่ระบุในวิธีการลงทะเบียนRegisterAttachedดั้งเดิม
เห็นได้ชัดเจนในรหัสที่ให้มา คำแนะนำเล็ก ๆ น้อย ๆ จะถูกซ่อนไว้ยังอยู่ในวิธีการลงทะเบียนคือสำหรับRegisterAttached
พารามิเตอร์เมตาดาต้าที่มีชื่อdefaultMetadata
ในขณะที่สำหรับมันเป็นชื่อRegister
typeMetadata
สำหรับคุณสมบัติที่แนบมาข้อมูลเมตาที่ระบุจะกลายเป็นข้อมูลเมตาเริ่มต้น อย่างไรก็ตามในกรณีของคุณสมบัติทั่วไปข้อมูลเมตาเริ่มต้นจะเป็นอินสแตนซ์ใหม่ที่PropertyMetadata
มีการDefaultValue
ตั้งค่าเท่านั้น(ไม่ว่าจะจากข้อมูลเมตาที่ให้มาหรือโดยอัตโนมัติ) เฉพาะการเรียกที่ตามมาเพื่อOverrideMetadata
ใช้ข้อมูลเมตาที่ให้มาจริงๆ
ข้อแตกต่างในทางปฏิบัติที่สำคัญคือในกรณีของคุณสมบัติทั่วไปCoerceValueCallback
และPropertyChangedCallback
ใช้ได้เฉพาะกับประเภทที่ได้รับจากประเภทที่ประกาศเป็นประเภทเจ้าของและสำหรับคุณสมบัติที่แนบมาคุณสมบัติเหล่านี้ใช้ได้กับทุกประเภท เช่นในสถานการณ์นี้:
var d = new DependencyObject();
d.SetValue(SomeClass.SomeProperty, "some value");
ผู้จดทะเบียนPropertyChangedCallback
จะถูกเรียกหากทรัพย์สินนั้นได้รับการจดทะเบียนเป็นทรัพย์สินที่แนบมา แต่จะไม่ถูกเรียกหากได้รับการจดทะเบียนเป็นทรัพย์สินปกติ CoerceValueCallback
เดียวกันไป
ความแตกต่างที่รองเกิดจากความจริงที่ว่าต้องการให้บุคลากรประเภทผลิตภัณฑ์จากOverrideMetadata
DependencyObject
ในทางปฏิบัติหมายความว่าประเภทเจ้าของสำหรับคุณสมบัติทั่วไปต้องได้มาจากDependencyObject
ในขณะที่คุณสมบัติที่แนบมาในสามารถเป็นประเภทใดก็ได้ (รวมถึงคลาสแบบคงที่โครงสร้าง enums ตัวแทน ฯลฯ )
นอกจากคำแนะนำของ @ MarqueIV แล้วในหลาย ๆ ครั้งฉันพบความคิดเห็นว่าคุณสมบัติปกติและคุณสมบัติที่แนบมานั้นแตกต่างกันไปตามวิธีที่สามารถใช้ในXAMLได้ กล่าวคือคุณสมบัติทั่วไปนั้นต้องการไวยากรณ์ของชื่อโดยนัยซึ่งตรงข้ามกับไวยากรณ์ของชื่อที่ชัดเจนซึ่งต้องการโดยคุณสมบัติที่แนบมา นี่ไม่เป็นความจริงในทางเทคนิคแม้ว่าในทางปฏิบัติมักจะเป็นเช่นนั้นก็ตาม เพื่อความชัดเจน:
<!-- Implicit property name -->
<ns:SomeClass SomeProperty="some value" />
<!-- Explicit property name -->
<DependencyObject ns:SomeClass.SomeProperty="some value" />
ในXAML แท้กฎเดียวที่ควบคุมการใช้ไวยากรณ์เหล่านี้มีดังต่อไปนี้:
การปฏิบัติตามเงื่อนไขเหล่านี้ช่วยให้คุณสามารถใช้ไวยากรณ์ที่เกี่ยวข้องได้ไม่ว่าคุณสมบัติการสำรองข้อมูลจะถูกลงทะเบียนเป็นปกติหรือแนบ
ตอนนี้ความเข้าใจผิดดังกล่าวเกิดจากความจริงที่ว่าบทช่วยสอนส่วนใหญ่ (พร้อมกับตัวอย่างโค้ดVisual Studio ในคลัง) สั่งให้คุณใช้คุณสมบัติCLRสำหรับคุณสมบัติการพึ่งพาปกติและรับ / ตั้งค่าตัวเข้าถึงสำหรับสิ่งที่แนบมา แต่ไม่มีอะไรหยุดคุณจากการใช้ทั้งสองอย่างในเวลาเดียวกันทำให้คุณสามารถใช้ไวยากรณ์แบบใดก็ได้ที่คุณต้องการ
คุณสมบัติที่แนบมาเป็นคุณสมบัติการพึ่งพาชนิดหนึ่ง ความแตกต่างอยู่ที่วิธีใช้
ด้วยคุณสมบัติที่แนบมาคุณสมบัติจะถูกกำหนดบนคลาสที่ไม่ใช่คลาสเดียวกันกับที่ใช้ โดยปกติจะใช้สำหรับการจัดวาง ตัวอย่างที่ดี ได้แก่ Panel.ZIndex หรือ Grid.Row - คุณใช้สิ่งนี้กับตัวควบคุม (เช่นปุ่ม) แต่จริงๆแล้วถูกกำหนดไว้ในแผงหรือตาราง คุณสมบัติ "แนบ" กับอินสแตนซ์ของปุ่ม
สิ่งนี้ช่วยให้คอนเทนเนอร์สามารถสร้างคุณสมบัติที่สามารถใช้กับ UIelement ใด ๆ
สำหรับความแตกต่างในการนำไปใช้ - โดยพื้นฐานแล้วเป็นเพียงเรื่องของการใช้ Register กับ RegisterAttached เมื่อคุณกำหนดคุณสมบัติ
คุณสมบัติที่แนบมาโดยทั่วไปมีไว้สำหรับองค์ประกอบคอนเทนเนอร์เช่นถ้าคุณมีกริดและคุณมี grid.row ตอนนี้ถือว่าเป็นคุณสมบัติที่แนบมาขององค์ประกอบกริดนอกจากนี้คุณสามารถใช้คุณสมบัตินี้ใน texbox ปุ่ม ฯลฯ เพื่อตั้งค่า วางในตาราง
คุณสมบัติการพึ่งพาเป็นเหมือนคุณสมบัติโดยทั่วไปเป็นของคลาสอื่นและใช้ในคลาสอื่น เช่นคุณมีรูปสี่เหลี่ยมผืนผ้าที่นี่ความสูงและความกว้างเป็นคุณสมบัติปกติของสี่เหลี่ยมผืนผ้า แต่ด้านซ้ายและด้านบนเป็นคุณสมบัติอ้างอิงเนื่องจากเป็นของคลาส Canvass
คุณสมบัติที่แนบมาเป็น DependencyProperties ชนิดพิเศษ ช่วยให้คุณสามารถแนบค่ากับวัตถุที่ไม่รู้อะไรเกี่ยวกับค่านี้ ตัวอย่างที่ดีสำหรับแนวคิดนี้คือแผงเค้าโครง แผงเค้าโครงแต่ละแผงต้องการข้อมูลที่แตกต่างกันเพื่อจัดแนวองค์ประกอบลูก Canvas ต้องการด้านบนและด้านซ้าย DockPanel ต้องใช้ Dock เป็นต้นเนื่องจากคุณสามารถเขียนแผงเลย์เอาต์ของคุณเองรายการจึงไม่มีที่สิ้นสุด คุณจะเห็นว่าเป็นไปไม่ได้ที่จะมีคุณสมบัติทั้งหมดบนคอนโทรล WPF ทั้งหมด สารละลายมีคุณสมบัติที่แนบมา ซึ่งกำหนดโดยตัวควบคุมที่ต้องการข้อมูลจากตัวควบคุมอื่นในบริบทเฉพาะ ตัวอย่างเช่นองค์ประกอบที่จัดแนวโดยแผงโครงร่างหลัก
ฉันคิดว่าคุณสามารถกำหนดคุณสมบัติที่แนบมาในคลาสได้เองหรือจะกำหนดในคลาสอื่นก็ได้ เราสามารถใช้คุณสมบัติที่แนบมาเพื่อขยายการควบคุมมาตรฐานของ Microsoft ได้เสมอ แต่คุณสมบัติการพึ่งพาคุณกำหนดไว้ในตัวควบคุมของคุณเอง เช่นคุณสามารถสืบทอดการควบคุมของคุณจากการควบคุมมาตรฐานและกำหนดคุณสมบัติการพึ่งพาในการควบคุมของคุณเองและใช้มัน สิ่งนี้เทียบเท่ากับการกำหนดคุณสมบัติที่แนบมาและใช้คุณสมบัติที่แนบนี้ในการควบคุมมาตรฐาน