วิธีการใช้หลายสไตล์ใน WPF


153

ใน WPF ฉันจะใช้หลายสไตล์กับ a ได้FrameworkElementอย่างไร? ตัวอย่างเช่นฉันมีตัวควบคุมที่มีสไตล์อยู่แล้ว ฉันยังมีสไตล์ที่แยกต่างหากซึ่งฉันต้องการจะเพิ่มเข้าไปโดยไม่ทำให้สไตล์แรกหายไป สไตล์นั้นมี TargetTypes ที่แตกต่างกันดังนั้นฉันจึงไม่สามารถขยายมันด้วยสไตล์อื่นได้


OP ไม่เคยระบุว่าสไตล์แรกของเขาจะไม่ซ้ำกันสำหรับการควบคุมเดียวเพียงอย่างเดียว คำตอบที่ให้ในหน้านี้ถือว่ามีความจำเป็นที่จะต้องแบ่งปันสไตล์ทั้งสองผ่านตัวควบคุมหลายตัว หากคุณกำลังมองหาวิธีการใช้สไตล์พื้นฐานในการควบคุมและแทนที่คุณสมบัติของแต่ละบุคคลโดยตรงบนตัวควบคุมแต่ละตัว: ดูคำตอบนี้: stackoverflow.com/a/54497665/1402498
JamesHoux

คำตอบ:


154

ฉันคิดว่าคำตอบง่ายๆคือคุณไม่สามารถทำได้ (อย่างน้อยใน WPF รุ่นนี้) สิ่งที่คุณพยายามทำ

นั่นคือสำหรับองค์ประกอบเฉพาะใด ๆ สามารถใช้สไตล์เดียวได้

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

ดังนั้นความคิดที่นี่ ... คือถ้าคุณสามารถแยกคุณสมบัติที่คุณต้องการตั้งค่า ... ตามลำดับชั้นการสืบทอดขององค์ประกอบที่คุณต้องการตั้งค่าหลายสไตล์ใน ... คุณอาจมีวิธีแก้ปัญหา

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <Style x:Key="baseStyle" TargetType="FrameworkElement">
            <Setter Property="HorizontalAlignment" Value="Left"/>
        </Style>
        <Style TargetType="Button" BasedOn="{StaticResource baseStyle}">
            <Setter Property="Content" Value="Hello World"/>
        </Style>
    </Page.Resources>
    <Grid>
        <Button Width="200" Height="50"/>
    </Grid>
</Page>


หวังว่านี่จะช่วยได้

บันทึก:

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

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <Style x:Key="baseStyle" TargetType="FrameworkElement">
            <Setter Property="HorizontalAlignment" Value="Left"/>
        </Style>
        <Style x:Key="derivedStyle" TargetType="ButtonBase" BasedOn="{StaticResource baseStyle}">
            <Setter Property="Content" Value="Hello World"/>
        </Style>
    </Page.Resources>
    <Grid>
        <Button Width="200" Height="50" Style="{StaticResource derivedStyle}"/>
    </Grid>
</Page>

10
โปรดจำไว้ว่า ... ** การสั่งซื้อเป็นสิ่งสำคัญ ** derivedStyleต้องมาหลังจากbaseStyle
SliverNinja - MSFT

50

Bea Stollnitz มีบล็อกโพสต์ที่ดีเกี่ยวกับการใช้ส่วนขยายมาร์กอัปสำหรับสิ่งนี้ภายใต้หัวข้อ "ฉันจะตั้งค่ารูปแบบหลายอย่างใน WPF ได้อย่างไร"

บล็อกนั้นตอนนี้ตายแล้วดังนั้นฉันจึงทำโพสต์ใหม่ที่นี่


ทั้ง WPF และ Silverlight เสนอความสามารถในการสืบทอดสไตล์จากสไตล์อื่นผ่านคุณสมบัติ“ BasedOn” คุณลักษณะนี้ช่วยให้นักพัฒนาสามารถจัดระเบียบสไตล์โดยใช้ลำดับชั้นที่คล้ายคลึงกับการสืบทอดคลาส พิจารณาสไตล์ต่อไปนี้:

<Style TargetType="Button" x:Key="BaseButtonStyle">
    <Setter Property="Margin" Value="10" />
</Style>
<Style TargetType="Button" x:Key="RedButtonStyle" BasedOn="{StaticResource BaseButtonStyle}">
    <Setter Property="Foreground" Value="Red" />
</Style>

ด้วยไวยากรณ์นี้ปุ่มที่ใช้ RedButtonStyle จะมีคุณสมบัติ Foreground ที่ตั้งค่าเป็นสีแดงและตั้งค่าคุณสมบัติระยะขอบเป็น 10

คุณลักษณะนี้อยู่ใน WPF มาเป็นเวลานานและเป็นคุณสมบัติใหม่ใน Silverlight 3

ถ้าคุณต้องการตั้งค่าสไตล์มากกว่าหนึ่งองค์ประกอบ WPF และ Silverlight ไม่มีวิธีแก้ปัญหาสำหรับปัญหานี้นอกกรอบ โชคดีที่มีวิธีการใช้พฤติกรรมนี้ใน WPF ซึ่งฉันจะพูดถึงในโพสต์บล็อกนี้

WPF และ Silverlight ใช้ส่วนขยายมาร์กอัปเพื่อจัดเตรียมคุณสมบัติที่มีค่าที่ต้องใช้ตรรกะในการจัดหา ส่วนขยายมาร์กอัปสามารถจดจำได้ง่ายโดยการมีวงเล็บปีกกาล้อมรอบพวกเขาใน XAML ตัวอย่างเช่นส่วนขยายมาร์กอัป {Binding} มีตรรกะเพื่อดึงค่าจากแหล่งข้อมูลและอัปเดตเมื่อมีการเปลี่ยนแปลงเกิดขึ้น ส่วนขยายมาร์กอัป {StaticResource} มีตรรกะเพื่อรับค่าจากพจนานุกรมทรัพยากรโดยยึดตามคีย์ โชคดีสำหรับเรา WPF อนุญาตให้ผู้ใช้เขียนส่วนขยายมาร์กอัปที่กำหนดเองของตัวเอง คุณลักษณะนี้ยังไม่ปรากฏใน Silverlight ดังนั้นโซลูชันในบล็อกนี้จึงสามารถใช้กับ WPF เท่านั้น

คนอื่น ๆได้เขียนวิธีแก้ปัญหาที่ดีในการผสานสองลักษณะโดยใช้ส่วนขยายมาร์กอัป อย่างไรก็ตามฉันต้องการโซลูชันที่ให้ความสามารถในการผสานสไตล์ไม่ จำกัด จำนวนซึ่งเป็นเรื่องยากเล็กน้อย

การเขียนส่วนขยายมาร์กอัปนั้นตรงไปตรงมา ขั้นตอนแรกคือการสร้างคลาสที่มาจาก MarkupExtension และใช้แอตทริบิวต์ MarkupExtensionReturnType เพื่อระบุว่าคุณต้องการให้ค่าที่ส่งคืนจากส่วนขยายมาร์กอัปของคุณเป็นประเภทของสไตล์

[MarkupExtensionReturnType(typeof(Style))]
public class MultiStyleExtension : MarkupExtension
{
}

การระบุอินพุตให้กับส่วนขยายมาร์กอัพ

เราต้องการให้ผู้ใช้ส่วนขยายมาร์กอัปของเราเป็นวิธีที่ง่ายในการระบุสไตล์ที่จะผสาน โดยพื้นฐานแล้วมีสองวิธีที่ผู้ใช้สามารถระบุอินพุตเป็นส่วนขยายมาร์กอัป ผู้ใช้สามารถตั้งค่าคุณสมบัติหรือส่งพารามิเตอร์ไปยังตัวสร้าง เนื่องจากในสถานการณ์นี้ผู้ใช้ต้องการความสามารถในการระบุสไตล์ไม่ จำกัด วิธีแรกของฉันคือการสร้างนวกรรมิกที่ใช้สตริงจำนวนเท่าใดก็ได้โดยใช้คีย์เวิร์ด“ params”:

public MultiStyleExtension(params string[] inputResourceKeys)
{
}

เป้าหมายของฉันคือสามารถเขียนอินพุตดังต่อไปนี้:

<Button Style="{local:MultiStyle BigButtonStyle, GreenButtonStyle}"  />

สังเกตเห็นว่าเครื่องหมายจุลภาคคั่นปุ่มลักษณะต่าง ๆ น่าเสียดายที่ส่วนขยายมาร์กอัปที่กำหนดเองไม่รองรับพารามิเตอร์คอนสตรัคเตอร์ไม่ จำกัด จำนวนดังนั้นวิธีการนี้ส่งผลให้เกิดข้อผิดพลาดในการคอมไพล์ ถ้าฉันรู้ล่วงหน้าว่ามีกี่รูปแบบที่ฉันต้องการผสานฉันสามารถใช้ไวยากรณ์ XAML เดียวกันกับตัวสร้างที่ใช้จำนวนสตริงที่ต้องการ:

public MultiStyleExtension(string inputResourceKey1, string inputResourceKey2)
{
}

เพื่อเป็นการหลีกเลี่ยงปัญหาฉันตัดสินใจให้พารามิเตอร์ตัวสร้างใช้สตริงเดี่ยวที่ระบุชื่อสไตล์คั่นด้วยช่องว่าง ไวยากรณ์ไม่เลวร้ายเกินไป:

private string[] resourceKeys;

public MultiStyleExtension(string inputResourceKeys)
{
    if (inputResourceKeys == null)
    {
        throw new ArgumentNullException("inputResourceKeys");
    }

    this.resourceKeys = inputResourceKeys.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

    if (this.resourceKeys.Length == 0)
    {
        throw new ArgumentException("No input resource keys specified.");
    }
}

การคำนวณเอาต์พุตของส่วนขยายมาร์กอัป

ในการคำนวณผลลัพธ์ของส่วนขยายมาร์กอัปเราจำเป็นต้องแทนที่เมธอดจาก MarkupExtension ที่เรียกว่า“ ProvideValue” ค่าที่ส่งคืนจากวิธีนี้จะถูกตั้งค่าในเป้าหมายของส่วนขยายมาร์กอัป

ฉันเริ่มต้นด้วยการสร้างวิธีการขยายสำหรับสไตล์ที่รู้วิธีผสานสองสไตล์ รหัสสำหรับวิธีนี้ค่อนข้างง่าย:

public static void Merge(this Style style1, Style style2)
{
    if (style1 == null)
    {
        throw new ArgumentNullException("style1");
    }
    if (style2 == null)
    {
        throw new ArgumentNullException("style2");
    }

    if (style1.TargetType.IsAssignableFrom(style2.TargetType))
    {
        style1.TargetType = style2.TargetType;
    }

    if (style2.BasedOn != null)
    {
        Merge(style1, style2.BasedOn);
    }

    foreach (SetterBase currentSetter in style2.Setters)
    {
        style1.Setters.Add(currentSetter);
    }

    foreach (TriggerBase currentTrigger in style2.Triggers)
    {
        style1.Triggers.Add(currentTrigger);
    }

    // This code is only needed when using DynamicResources.
    foreach (object key in style2.Resources.Keys)
    {
        style1.Resources[key] = style2.Resources[key];
    }
}

ด้วยตรรกะด้านบนสไตล์แรกจะถูกปรับเปลี่ยนเพื่อรวมข้อมูลทั้งหมดจากวินาที หากมีข้อขัดแย้ง (เช่นทั้งสองลักษณะมีตัวตั้งค่าสำหรับคุณสมบัติเดียวกัน) รูปแบบที่สองจะชนะ โปรดสังเกตว่านอกเหนือจากการคัดลอกสไตล์และทริกเกอร์ฉันยังคำนึงถึงค่า TargetType และ BasedOn รวมถึงทรัพยากรใด ๆ ที่สไตล์ที่สองอาจมี สำหรับ TargetType ของสไตล์ที่ผสานฉันใช้ชนิดใดก็ได้ที่ได้รับมากกว่า หากสไตล์ที่สองมีสไตล์ BasedOn ฉันจะรวมลำดับชั้นของสไตล์ไว้ซ้ำ หากมีทรัพยากรฉันจะคัดลอกไปยังรูปแบบแรก หากทรัพยากรเหล่านั้นถูกอ้างถึงโดยใช้ {StaticResource} พวกเขาจะได้รับการแก้ไขแบบคงที่ก่อนที่โค้ดผสานนี้จะทำงานและดังนั้นจึงไม่จำเป็นต้องย้าย ฉันเพิ่มรหัสนี้ในกรณีที่เราใช้ DynamicResources

วิธีการส่วนต่อขยายที่แสดงด้านบนเปิดใช้งานไวยากรณ์ต่อไปนี้:

style1.Merge(style2);

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

<Button Style="{local:MultiStyle {StaticResource BigButtonStyle}, {StaticResource GreenButtonStyle}}"/>
public MultiStyleExtension(params Style[] styles)
{
}

แต่นั่นไม่ได้ผล และแม้ว่าข้อ จำกัด params ไม่มีอยู่เราก็อาจจะมีข้อ จำกัด อีกอย่างหนึ่งของส่วนขยายมาร์กอัปซึ่งเราจะต้องใช้ไวยากรณ์องค์ประกอบองค์ประกอบแทนไวยากรณ์แอตทริบิวต์เพื่อระบุทรัพยากรคงที่ซึ่งเป็น verbose และยุ่งยาก (ฉันอธิบายสิ่งนี้ บั๊กดีกว่าในโพสต์บล็อกก่อนหน้า ) และแม้ว่าข้อ จำกัด ทั้งสองนั้นไม่มีอยู่ฉันก็ยังอยากจะเขียนรายการของสไตล์โดยใช้เพียงชื่อของมัน - มันสั้นกว่าและอ่านง่ายกว่า StaticResource สำหรับแต่ละข้อ

วิธีแก้ไขคือการสร้าง StaticResourceExtension โดยใช้รหัส รับคีย์สไตล์ของสตริงประเภทและผู้ให้บริการฉันสามารถใช้ StaticResourceExtension เพื่อดึงอินสแตนซ์ของสไตล์ที่แท้จริง นี่คือไวยากรณ์:

Style currentStyle = new StaticResourceExtension(currentResourceKey).ProvideValue(serviceProvider) as Style;

ตอนนี้เรามีชิ้นส่วนทั้งหมดที่จำเป็นในการเขียนวิธี ProvValue:

public override object ProvideValue(IServiceProvider serviceProvider)
{
    Style resultStyle = new Style();

    foreach (string currentResourceKey in resourceKeys)
    {
        Style currentStyle = new StaticResourceExtension(currentResourceKey).ProvideValue(serviceProvider) as Style;

        if (currentStyle == null)
        {
            throw new InvalidOperationException("Could not find style with resource key " + currentResourceKey + ".");
        }

        resultStyle.Merge(currentStyle);
    }
    return resultStyle;
}

นี่คือตัวอย่างที่สมบูรณ์ของการใช้งานส่วนขยายมาร์กอัป MultiStyle:

<Window.Resources>
    <Style TargetType="Button" x:Key="SmallButtonStyle">
        <Setter Property="Width" Value="120" />
        <Setter Property="Height" Value="25" />
        <Setter Property="FontSize" Value="12" />
    </Style>

    <Style TargetType="Button" x:Key="GreenButtonStyle">
        <Setter Property="Foreground" Value="Green" />
    </Style>

    <Style TargetType="Button" x:Key="BoldButtonStyle">
        <Setter Property="FontWeight" Value="Bold" />
    </Style>
</Window.Resources>

<Button Style="{local:MultiStyle SmallButtonStyle GreenButtonStyle BoldButtonStyle}" Content="Small, green, bold" />

ป้อนคำอธิบายรูปภาพที่นี่


3
ทางออกที่ดีจริงๆ แต่ฉันไม่เข้าใจว่าทำไมไม่มีวิธีง่ายๆในการผสาน 3 หรือ + สไตล์
Mr Rubix

31

แต่คุณสามารถขยายจากที่อื่น .. ลองดูที่คุณสมบัติ BasedOn

<Style TargetType="TextBlock">
      <Setter Property="Margin" Value="3" />
</Style>

<Style x:Key="AlwaysVerticalStyle" TargetType="TextBlock" 
       BasedOn="{StaticResource {x:Type TextBlock}}">
     <Setter Property="VerticalAlignment" Value="Top" />
</Style>

นี่ก็เพียงพอแล้วสำหรับฉัน tnks!
เดวิดเลย์

แต่จะใช้งานได้ก็ต่อเมื่อสไตล์ทั้งสองเป็นประเภทเดียวกัน (ข้อผิดพลาด XAML: "สามารถยึดตามสไตล์ที่มีประเภทเป้าหมายเป็นประเภทฐาน '<type>' เท่านั้น)
Krzysztof Bociurko

17

WPF / XAML ไม่ได้มีฟังก์ชั่นนี้ แต่ให้ความสามารถในการขยายเพื่อให้คุณทำสิ่งที่คุณต้องการ

เราวิ่งเข้าไปในความต้องการเดียวกันและจบลงด้วยการสร้าง XAML Markup Extension ของเราเอง (ซึ่งเราเรียกว่า "MergedStylesExtension") เพื่อให้เราสามารถสร้างสไตล์ใหม่จากสองสไตล์อื่น ๆ (ซึ่งหากจำเป็นอาจใช้หลายครั้งใน แถวเพื่อสืบทอดจากสไตล์มากยิ่งขึ้น)

เนื่องจากข้อผิดพลาด WPF / XAML เราจำเป็นต้องใช้ไวยากรณ์ขององค์ประกอบคุณสมบัติเพื่อใช้ แต่นอกเหนือจากนั้นดูเหมือนว่าจะใช้ได้ เช่น,

<Button
    Content="This is an example of a button using two merged styles">
    <Button.Style>
      <ext:MergedStyles
                BasedOn="{StaticResource FirstStyle}"
                MergeStyle="{StaticResource SecondStyle}"/>
   </Button.Style>
</Button>

ฉันเพิ่งเขียนเกี่ยวกับที่นี่: http://swdeveloper.wordpress.com/2009/01/03/wpf-xaml-multiple-style-inheritance-and-markup-extensions/


3

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

<TextBlock Text="Test"
    local:CompoundStyle.StyleKeys="headerStyle,textForMessageStyle,centeredStyle"/>

หวังว่าจะช่วย


2

ใช้AttachedPropertyเพื่อตั้งค่าหลายสไตล์เช่นรหัสต่อไปนี้:

public class Css
{

    public static string GetClass(DependencyObject element)
    {
        if (element == null)
            throw new ArgumentNullException("element");

        return (string)element.GetValue(ClassProperty);
    }

    public static void SetClass(DependencyObject element, string value)
    {
        if (element == null)
            throw new ArgumentNullException("element");

        element.SetValue(ClassProperty, value);
    }


    public static readonly DependencyProperty ClassProperty =
        DependencyProperty.RegisterAttached("Class", typeof(string), typeof(Css), 
            new PropertyMetadata(null, OnClassChanged));

    private static void OnClassChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ui = d as FrameworkElement;
        Style newStyle = new Style();

        if (e.NewValue != null)
        {
            var names = e.NewValue as string;
            var arr = names.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var name in arr)
            {
                Style style = ui.FindResource(name) as Style;
                foreach (var setter in style.Setters)
                {
                    newStyle.Setters.Add(setter);
                }
                foreach (var trigger in style.Triggers)
                {
                    newStyle.Triggers.Add(trigger);
                }
            }
        }
        ui.Style = newStyle;
    }
}

Usege:

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:style_a_class_like_css"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="325">
    <Window.Resources>

        <Style TargetType="TextBlock" x:Key="Red" >
            <Setter Property="Foreground" Value="Red"/>
        </Style>

        <Style TargetType="TextBlock" x:Key="Green" >
            <Setter Property="Foreground" Value="Green"/>
        </Style>

        <Style TargetType="TextBlock" x:Key="Size18" >
            <Setter Property="FontSize" Value="18"/>
            <Setter Property="Margin" Value="6"/>
        </Style>

        <Style TargetType="TextBlock" x:Key="Bold" >
            <Setter Property="FontWeight" Value="Bold"/>
        </Style>

    </Window.Resources>
    <StackPanel>

        <Button Content="Button" local:Css.Class="Red Bold" Width="75"/>
        <Button Content="Button" local:Css.Class="Red Size18" Width="75"/>
        <Button Content="Button" local:Css.Class="Green Size18 Bold" Width="75"/>

    </StackPanel>
</Window>

ผลลัพธ์:

ป้อนคำอธิบายรูปภาพที่นี่


1

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


1

คุณอาจจะได้สิ่งที่คล้ายกันถ้าใช้สิ่งนี้กับคอลเลกชันของรายการโดยใช้ StyleSelector ฉันได้ใช้วิธีนี้เพื่อเข้าถึงปัญหาที่คล้ายกันในการใช้สไตล์ที่แตกต่างบน TreeViewItems ขึ้นอยู่กับประเภทวัตถุที่ถูกผูกไว้ในต้นไม้ คุณอาจต้องแก้ไขคลาสด้านล่างเล็กน้อยเพื่อปรับให้เข้ากับวิธีการเฉพาะของคุณ แต่หวังว่าสิ่งนี้จะช่วยให้คุณเริ่มต้นได้

public class MyTreeStyleSelector : StyleSelector
{
    public Style DefaultStyle
    {
        get;
        set;
    }

    public Style NewStyle
    {
        get;
        set;
    }

    public override Style SelectStyle(object item, DependencyObject container)
    {
        ItemsControl ctrl = ItemsControl.ItemsControlFromItemContainer(container);

        //apply to only the first element in the container (new node)
        if (item == ctrl.Items[0])
        {
            return NewStyle;
        }
        else
        {
            //otherwise use the default style
            return DefaultStyle;
        }
    }
}

จากนั้นคุณใช้สิ่งนี้เช่นกัน

 <TreeView>
     <TreeView.ItemContainerStyleSelector
         <myassembly: MyTreeStyleSelector DefaultStyle = "{StaticResource DefaultItemStyle}"
                                         NewStyle = "{StaticResource NewItemStyle}" />
     </TreeView.ItemContainerStyleSelector>
  </ TreeView>

1

บางครั้งคุณสามารถเข้าถึงวิธีนี้ได้ด้วยการซ้อนแผง สมมติว่าคุณมีสไตล์ที่มีการเปลี่ยนแปลงพื้นหน้าและการเปลี่ยนแปลงอื่น FontSize คุณสามารถใช้รูปแบบหลังใน TextBlock และวางไว้ในกริดซึ่งสไตล์ของมันเป็นรูปแบบแรก สิ่งนี้อาจช่วยและอาจเป็นวิธีที่ง่ายที่สุดในบางกรณีแม้ว่ามันจะไม่สามารถแก้ปัญหาทั้งหมดได้


1

เมื่อคุณแทนที่ SelectStyle คุณจะได้รับคุณสมบัติ GroupBy ผ่านการสะท้อนเช่นด้านล่าง:

    public override Style SelectStyle(object item, DependencyObject container)
    {

        PropertyInfo p = item.GetType().GetProperty("GroupBy", BindingFlags.NonPublic | BindingFlags.Instance);

        PropertyGroupDescription propertyGroupDescription = (PropertyGroupDescription)p.GetValue(item);

        if (propertyGroupDescription != null && propertyGroupDescription.PropertyName == "Title" )
        {
            return this.TitleStyle;
        }

        if (propertyGroupDescription != null && propertyGroupDescription.PropertyName == "Date")
        {
            return this.DateStyle;
        }

        return null;
    }

0

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

เป็นเรื่องธรรมดามากที่จะต้องปรับแต่งพารามิเตอร์ต่อองค์ประกอบแต่ละรายการ การกำหนดรูปแบบพจนานุกรมสำหรับใช้กับองค์ประกอบเดียวนั้นยุ่งยากมากในการรักษาหรือทำให้เข้าใจ เพื่อหลีกเลี่ยงการสร้างสไตล์สำหรับการปรับแต่งองค์ประกอบแบบครั้งเดียวอ่านคำตอบของคำถามของฉันที่นี่ที่นี่:

https://stackoverflow.com/a/54497665/1402498

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.