You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将DataTemplate注入WPF自定义Style/UserControl实现棋盘复用?

查看更新获取解决方案

我开发了一个小型WPF应用,包含扫雷、四子棋、井字棋等多款小游戏的克隆版。

这些游戏的共同特点是都由统一网格的方块组成,每个方块由按钮控制。

我为每个游戏都定义了一个UserControl,其XAML中包含UniformGrid类型的ItemsPanelTemplate。

它们唯一的区别在于所使用的DataTemplate:

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <!-- 满足游戏特定需求的按钮 -->
    </DataTemplate>           
</ItemsControl.ItemTemplate>

为避免重复代码,我希望创建一个带有DataTemplate依赖属性的UserControl(其XAML中定义了名为itemscontrol的ItemsControl):

public DataTemplate DataTemplate
{
    get => (DataTemplate)GetValue(DataTemplateProperty);
    set => SetValue(DataTemplateProperty, value);
}
public static readonly DependencyProperty DataTemplateProperty =
        DependencyProperty.Register("DataTemplate", typeof(DataTemplate), typeof(BoardGameControl));

public BoardGameControl()
{
    InitializeComponent();
    itemscontrol.ItemTemplate = DataTemplate;
}

我尝试在应用中这样使用它:

<controls:BoardGameControl>
    <controls:BoardGameControl.DataTemplate>
        <DataTemplate>
            <Button Content="Hi"/>
        </DataTemplate>
    </controls:BoardGameControl.DataTemplate>
</controls:BoardGameControl>

我还尝试了其他方法,但都没成功。

如何避免为每个游戏定义新的ItemsControl,转而使用可根据场景适配不同按钮的UserControl或Style?

更新

我结合了标记为已采纳的解决方案和@Joe的评论。

我没有使用UserControl,而是创建了一个带有所需属性的自定义控件,并在Generic.xaml文件中为其设置样式。我还移除了自定义控件中的DataTemplate属性,改为在App.xaml中为每个不同的视图模型添加DataTemplate。

以下是我的新自定义控件的后台代码和样式:

public class GameBoardControl : Control
{
    public int Columns
    {
        get => (int)GetValue(ColumnsProperty);
        set => SetValue(ColumnsProperty, value);
    }
    public static readonly DependencyProperty ColumnsProperty =
        DependencyProperty.Register(nameof(Columns), typeof(int), typeof(BoardGameControl));

    public int Rows
    {
        get => (int)GetValue(RowsProperty);
        set => SetValue(RowsProperty, value);
    }
    public static readonly DependencyProperty RowsProperty =
        DependencyProperty.Register(nameof(Rows), typeof(int), typeof(BoardGameControl));

    static GameBoardControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(GameBoardControl), new FrameworkPropertyMetadata(typeof(GameBoardControl)));
    }
}
<Style TargetType="{x:Type controls:GameBoardControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type controls:GameBoardControl}">
                <ItemsControl ItemsSource="{Binding Squares}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <UniformGrid Columns="{Binding Columns, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls:GameBoardControl}}}"
                                         Rows="{Binding Rows, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls:GameBoardControl}}}"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

请注意,我始终将ItemsSource绑定到Squares,因为所有游戏都有一个名为Squares的ObservableCollection,用于存储方块视图模型。

DataTemplate示例:

<DataTemplate DataType="{x:Type mvvmtoolkit:MemorySquareVM}">
        <Button Command="{Binding RelativeSource={RelativeSource AncestorType=controls:GameBoardControl}, Path=DataContext.PressSquareCommand}" 
                CommandParameter="{Binding}"
                Background="{Binding Position, Converter={local:PositionToColorConverter}}"
                Style="{StaticResource MemoryButton}"/>
</DataTemplate>

内容的提问来源于stack exchange,提问作者Silop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 02:30:52