WPF绑定用户控件

本文关键字:控件 用户 绑定 WPF | 更新日期: 2023-09-27 17:49:42

我一直在寻找解决这个问题的方法。我有一个标签适配器类,我用它来填充标签控件

public partial class TabAdapter : UserControl
{
    public static readonly DependencyProperty fileNameProperty =
        DependencyProperty.Register(
            "fileName",
            typeof(string),
            typeof(TabAdapter),
            new FrameworkPropertyMetadata(
                string.Empty,
                FrameworkPropertyMetadataOptions.AffectsRender,
                new PropertyChangedCallback(OnFileNamePropertyChanged),
                new CoerceValueCallback(coerceFileName)
                ),
            new ValidateValueCallback(fileNameValidationCallback)
        );
    public TabAdapter()
    {
        InitializeComponent();
        //initializeInterior();
        CreateSaveCommand();
        TabAdapterContent.DataContext = this;
        Console.WriteLine("constructor hit.");
    }
    public string fileName
    {
        get { return (string)GetValue(fileNameProperty); }
        set { SetValue(fileNameProperty, value); }
    }
    private ColumnMapper _columnMap;
    private TableMapper _tableMap;
    private TabType tabType;
    private enum TabType { TABLE_MAPPER, COLUMN_MAPPER, ERROR_MSG }
    private static object coerceFileName(DependencyObject d, object value)
    {
        return fileName;
    }
    private static bool fileNameValidationCallback(object Value)
    {
        string fn = (string)Value;
        if (fn.Equals(string.Empty))
        {
            return true;
        }
        FileInfo fi = new FileInfo(fn);
        return ((fi.Exists && fi.Extension.Equals(".csv")));
    }
    private static void OnFileNamePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
    {
        TabAdapter source = d as TabAdapter;
        Console.WriteLine("got to property changer: " + (string)args.NewValue + " :new / old: " + (string)args.OldValue);
        source.initializeInterior();
    }
    private void initializeInterior()
    {
        Console.WriteLine("initializing Interior filename: " + fileName);
        if (Regex.IsMatch(fileName, @".*_SourceTableMapping.csv$"))
        {
            tabType = TabType.TABLE_MAPPER;
            _tableMap = new TableMapper(fileName);
            Grid.SetRow(_tableMap, 0);
            Grid.SetColumn(_tableMap, 0);
            //clear out the content.
            this.TabAdapterContent.Children.Clear();
            //add new content
            this.TabAdapterContent.Children.Add(_tableMap);
        }
        else if (fileName.EndsWith(".csv"))
        {
            tabType = TabType.TABLE_MAPPER;
            _columnMap = new ColumnMapper(fileName);
            Grid.SetRow(_columnMap, 0);
            Grid.SetColumn(_columnMap, 0);
            //clear out the content.
            this.TabAdapterContent.Children.Clear();
            //add new content
            this.TabAdapterContent.Children.Add(_columnMap);
        }
        else
        {
            tabType = TabType.ERROR_MSG;
            TextBlock tb = new TextBlock();
            tb.Text = "The File: " + fileName + " is not a valid mapping file.";
            Grid.SetRow(tb, 0);
            Grid.SetColumn(tb, 0);
            //clear out the content.
            this.TabAdapterContent.Children.Clear();
            //add new content
            this.TabAdapterContent.Children.Add(tb);
        }
    }
}

这样做的目的是决定要添加什么类型的文件,并在其中加载正确的用户控件以显示该文件。

TAB控件的主窗口xaml是

<TabControl x:Name="tabControl" Grid.Column="1" Grid.Row="0" ItemsSource="{Binding openFileNames, Mode=OneWay}">
            <TabControl.LayoutTransform>
                <!-- Allows to zoom the control's content using the slider -->
                <ScaleTransform CenterX="0"
                     CenterY="0" />
                <!-- part of scale transform ScaleX="{Binding ElementName=uiScaleSlider,Path=Value}"
                     ScaleY="{Binding ElementName=uiScaleSlider,Path=Value}" />-->
            </TabControl.LayoutTransform>
            <!-- Header -->
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Header}" />
                </DataTemplate>
            </TabControl.ItemTemplate>
            <!-- Content -->
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <local:TabAdapter fileName="{Binding fileName}" />
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>

头可以工作,如果我改变

<local:TabAdapter fileName="{Binding fileName}" />

<TextBlock Text="{Binding fileName}" />

然后它都正确绑定,我有一种感觉,它与我的选项卡适配器上的数据上下文有关。但不确定需要设置成什么

TAB适配器的xaml是

<UserControl x:Class="ImportMappingGui.TabAdapter"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         mc:Ignorable="d"
         d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="TabAdapterContent">
    <Grid.RowDefinitions>
        <RowDefinition Height = "*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
</Grid>

将全部编译并运行,但只有用户控件的构造函数被击中,而且无论我创建了多少制表符,都只击中一次。这是我的第一个WPF应用程序,所以我的道歉,如果它是愚蠢的东西我错过了。(或者如果我设置各种适配器的方法不是解决此问题的最佳方法)。

WPF绑定用户控件

不要从UserControl本身设置UserControlDataContext。它破坏了"不好看"控件的全部意义,这些控件可以用来显示你传递给它的任何东西。

您的fileName绑定失败,因为DataContext = thisthisTabAdapter控件本身,而TabAdapter.fileName实际上没有设置为任何东西。(请记住,绑定告诉属性在其他地方检索它的值与直接设置值是不同的)

对于不运行一次以上的构造函数,这是设计的。由于您告诉TabControl使用TabAdapter控件作为模板,因此它将创建TabAdapter的一个副本,并在切换选项卡时简单地替换控件后面的.DataContext。这提高了性能,因为它不必为每个选项卡保持初始化和跟踪单独的控件,并减少了内存的使用。