WPF数据绑定用户控件

时间:2015-05-19 16:53:31

标签: c# wpf xaml data-binding

我一直在寻找解决方案的时间。 我有一个选项卡适配器类,我用来填充选项卡控件

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);
        }
    }
}

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

标签控件的主窗口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}" />

然后它都正确绑定,我感觉它与我的选项卡适配器上的数据上下文有关。但不完全确定需要设置的内容。

我的选项卡适配器的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应用程序,所以我很抱歉,如果它是一个愚蠢的我缺少。 (或者,如果我设置各种适配器的方法不是解决此问题的最佳方法)。

1 个答案:

答案 0 :(得分:0)

不要在UserControl本身内设置DataContext的{​​{1}}。它打败了“无望”的全部观点。可以用来显示你传递的任何内容的控件。

您的UserControl绑定失败,因为fileNameDataContext = thisthis控件本身,而TabAdapter实际上并未设置为任何内容。 (请记住,绑定告诉属性在其他地方检索它的值与直接设置值不同)

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