开发者

WPF - Rethinking control inheritance

I'm writing an application that loads in records from an XML file and uses them to populate forms. It's for a card game, so I want the forms to display different fields and have different looks depending on the particular record (specifically depending on the 'CardType' field in the record).

In vanilla C#, I would create a base window which held a record, then inherit from it for each specific type, changing the visuals of the window. Then I would check the Type, instantiate the correct window and populate it.

In WPF, inheriting from windows is not allowed, so the solution is to use a single window and then use styles/templates to adjust the window depending on the circumstances.

Initially I created completely separate windows, passed the appropriate one a class holding the record data which was used to set the DataContext.

However, now I'm trying to do things right I'm struggling to grasp the exact approach. I've tried creating a control template within a style that contains the controls to hold my fields, with binding to populate the fields...

    <Style TargetType="{x:Type Label}" x:Key="testLabel">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Label}">
                    <Grid>
                        <Rectangle Fill="White" Stroke="Black" StrokeThickness="3" RadiusX="20" RadiusY="20" />
                        <DockPanel LastChildFill="False" Margin="10">
                            <DockPanel DockPanel.Dock="Top">
                                <Grid VerticalAlignment="Top" DockPanel.Dock="Left">
                                    <Ellipse Height="25" Width="25" Stroke="Black" StrokeThickness="2" Fill="Red"/>
                                    <TextBlock Name="textLevel" Foreground="Black" FontSize="15" TextAlignment="Center" VerticalAlignment="Center" Text="{Binding Level, UpdateSourceTrigger=PropertyChanged}"/>
                                </Grid>
                                <DockPanel DockPanel.Dock="Top">
                                    <TextBlock Name="textType" Foreground="Black" FontSize="15" FontWeight="Bold" FontStyle="Italic" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="10, 0, 10, 0" DockPanel.Dock="Right" Text="{Binding CardType, UpdateSourceTrigger=PropertyChanged}"/>       
                                    <TextBlock Name="textName" Foreground="Black" FontSize="20" FontWeight="Bold" Margin="10, 0, 10, 0"开发者_如何学编程 DockPanel.Dock="Left" Text="{Binding CardName, UpdateSourceTrigger=PropertyChanged}"/>      
                                </DockPanel>
                                <TextBlock Name="textPronounciation" Foreground="DarkSlateGray" FontSize="12" Margin="10, 0, 10, 0" DockPanel.Dock="Top" Text="{Binding Pronounciation, UpdateSourceTrigger=PropertyChanged}"/>
                            </DockPanel>
                            <Rectangle Name="rectPicture" Width="280" Height="210" Margin="0, 5" DockPanel.Dock="Top"/>
                            <TextBlock Name="textLineage" Foreground="Black" FontSize="15" Margin="10, 0, 10, 0" DockPanel.Dock="Top" Text="{Binding Lineage, UpdateSourceTrigger=PropertyChanged}"/>
                            <TextBlock Name="textFlavourText" Foreground="Black" FontSize="11" TextWrapping="Wrap" Margin="10, 0, 10, 0" DockPanel.Dock="Top" Text="{Binding FlavourText, UpdateSourceTrigger=PropertyChanged}"/>
                            <TextBlock Name="textQuote" Foreground="Black" FontSize="11" TextWrapping="Wrap" Margin="10, 5, 10, 0" DockPanel.Dock="Top" Text="{Binding Quote, UpdateSourceTrigger=PropertyChanged}"/>
                            <TextBlock Name="textAttribution" Foreground="Black" FontSize="9" FontWeight="Bold" TextWrapping="Wrap" HorizontalAlignment="Right" Margin="10, 0, 10, 0" DockPanel.Dock="Top" Text="{Binding Attribution, UpdateSourceTrigger=PropertyChanged}"/>
.
.
.

...but it doesn't populate.

Is dynamic binding allowed within a control template, or should I be doing something different?

(Hopefully) All the relevant code follows:

From the calling function:

    private void ShowCard(CardDetails record)
    {
        CardLayout layout = new CardLayout(record);
        CardWindow displayedCard = new CardWindow(layout);
        displayedCard.Show();
    }

CardLayout class - To be populated with the data by the control template. I used label as it seemed the simplest control, as I was going to be replacing its logical tree anyway:

<Label x:Class="Cards.CardLayout"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Style="{StaticResource testLabel}">
</Label>

.

public partial class CardLayout : Label
{
    public CardLayout()
    {
        InitializeComponent();
    }

    public CardLayout(CardDetails dataIn)
    {
        InitializeComponent();
        Initialise(dataIn);
    }

    public void Initialise(CardDetails dataIn)
    {
        this.DataContext = dataIn;
    }
}

CardWindow class - holds the CardLayout as a child - the intention is eventually have different windows which hold different numbers of CardLayouts.

<Window x:Class="Cards.CardWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <Grid Name="gridCard">

    </Grid>
</Window>

.

public partial class CardWindow : Window
{
    public CardWindow()
    {
        InitializeComponent();
    }

    public CardWindow(CardLayout dataIn)
    {
        InitializeComponent();
        Initialise(dataIn);
    }

    public void Initialise(CardLayout dataIn)
    {
        gridCard.Children.Add(dataIn);
    }
}

So when it runs, I'm expecting a window holding a grid that holds a label that has had its logical tree replaced with the ControlTemplate and populated via dynamic binding.

Sorry for the rambling question, I don't know if I doing the right thing in the wrong way, or I should scrap all this and approach it in a different way.


While waiting for an answer, I simplified everything, starting with hard-wired values, then gradually adding a step until I got it working. Now I've fleshed it all out, I can't see what I'm doing differently.

For completeness, here's my simplified ControlTemplate which works with the code in the question:

<Application.Resources>
    <Style TargetType="{x:Type Label}" x:Key="testWindow4">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Label}">
                    <Grid>
                        <TextBlock Text="{Binding CardName}"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Application.Resources>

Where CardName is a String property in CardDetails.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜