单独绑定到模板化控件的多个实例

本文关键字:实例 模板化控件 绑定 单独 | 更新日期: 2023-09-27 18:05:40

我希望使用模板和MVVM模式创建类似控件的网格。下面是对我遇到的问题的简单描述。我首先为网格的每个元素定义一个类Element:

public class Element : INotifyPropertyChanged
{
    private string _dText = "Default";
    public string dText { get { return _dText; } set { _dText = value; NotifyPropertyChanged("dText"); } }
    internal Element(string aText) { dText = aText; }
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(info));
    }
}

然后我在ViewModel类中实例化一些元素,该类是页面的DataContext,如下所示:

public class MinVM
{
    private Element _element0 = new Element("Element0 initialization text 0");
    public Element element0 { get { return _element0; } set { _element0 = value; } }
    private Element _element1 = new Element("Element1 initialization text 1");
    public Element element1 { get { return _element1; } set { _element1 = value; } }
}

现在,在XAML页面。我创建了一个ControlTemplate,目的是让我得到一些很好的居中文本,如下所示:

    <ControlTemplate x:Name="cTemplate" x:Key="CTemplate" TargetType="ContentControl">
        <Grid x:Name="ctGrid" Background="Orange" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <TextBox x:Name ="dtBox" Background="Orange" BorderThickness="0" 
                VerticalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"
                Text="{Binding dText, FallbackValue=Default control template text}">
            </TextBox>
        </Grid>
    </ControlTemplate>

最后,在Page内容本身,我实例化网格和其中的元素,如下所示:

    <ContentControl x:Name="element0" Grid.Row="0" Template="{StaticResource CTemplate}" Content="{Binding Path=element0}"></ContentControl>
    <ContentControl x:Name="element1" Grid.Row="1" Template="{StaticResource CTemplate}" Content="{Binding Path=element1}"></ContentControl>

这一切都呈现得很好,正如你所期望的,但是绑定不起作用,也就是说,我不能改变默认文本,因为WPF正在MinVM中寻找字段dText,而不是在元素中。这是因为ControlTemplate忽略了Content="{Binding Path=element0}"

尝试和修复它的明显方法是使用DataTemplate而不是ControlTemplate。我已经这样做了-创建了一个DataTemplate与上面的ControlTemplate完全相同的内部,Key="DTemplate"。然后将实例化XAML更改为

    <ContentControl x:Name="element0" Grid.Row="0" ContentTemplate="{StaticResource DTemplate}" Content="{Binding Path=element0}"></ContentControl>
    <ContentControl x:Name="element1" Grid.Row="1" ContentTemplate="{StaticResource DTemplate}" Content="{Binding Path=element1}"></ContentControl>

现在绑定工作正常,正如您所期望的那样—我可以愉快地更改控件文本。但是渲染不再正常工作(文本不再在Grid元素中居中,并且橙色不再填充Grid单元格),因为我已经丢失了ControlTemplate

所以,我可以让它正确渲染,或者绑定,但不能两者都要

单独绑定到模板化控件的多个实例

如果我正确理解你需要什么,那么下面的XAML适合我(你可以提取样式):

<Window x:Class="WpfScratch.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:WpfScratch"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="ContentTemplate">
            <TextBox TextAlignment="Center" Text="The obvious way to try and fix it is to use a DataTemplate instead of a ControlTemplate. I've done that - created a DataTemplate with exactly the same internals as the above ControlTemplate, with Key=DTemplate. I then change the instantiation XAML to" TextWrapping="Wrap"/>
        </DataTemplate>
        <Style x:Key="ContentControlStyle1" TargetType="{x:Type ContentControl}">
            <Setter Property="HorizontalAlignment" Value="Stretch"/>
            <Setter Property="VerticalAlignment" Value="Stretch"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="ContentTemplate" Value="{StaticResource ContentTemplate}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ContentControl}">
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <ContentControl Margin="4" Style="{DynamicResource ContentControlStyle1}"/>
    </Grid>
</Window>