繁体   English   中英

WPF将控件绑定到另一个控件

[英]WPF Binding control to another control

我有以下WPF窗口。 更改#Cables的值会向TabControl (C2,C3,C4 ...)添加(或删除)标签。 更改#Phase会向DataGrid添加新行。

窗口

所有选项卡(除了“选项”之外)均具有相同的格式,因此我创建了一个UserControl NTab类,该类具有自己的.xaml和代码后置。

现在,每个其他选项卡将具有一个ComboBox ,用户可以在其中选择适当的“阶段”(通过name属性)。 为此, NTab需要在“选项”选项卡中了解Phase DatGrid 我的代码当前分为两类:

  • MainWindow ,包含整个窗口和“选项”选项卡的代码(.xaml及其后置代码);
  • NTab ,其NTab包含代码(.xaml和背后代码)。

该阶段DataGrid's ItemSourceObservableCollection ,我这样做有什么被送到收集到NTab构造和它并列.CollectionChanged事件以下NTab功能(阶段是一个ObservableCollection<string>依赖属性):

public void PhasesChanged(object source, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    var pC = source as ObservableCollection<NPhase>;
    Phases.Clear();
    for (int i = 0; i < pC.Count; i++)
        Phases.Add("" + (i + 1));
}

这将创建DataGrid数据的副本(只是名称),并将其作为绑定到ComboBox的依赖项属性存储在每个NTab中。 这可行。

我的问题是,是否有更好的方法可以做到这一点。 我宁愿不必创建数据的“冗余”副本,也希望能够将ComboBoxes直接绑定到DataGrid 这可能吗?


编辑:添加我的代码。 我已删除了与该问题无关的.xaml和代码隐藏部分。

MainWindow.xaml

<Window x:Class="WPF.MainWindow"
    x:Name="Main"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    xmlns:l="clr-namespace:WPF"
    Title="WPF" SizeToContent="WidthAndHeight">
<TabControl Name="tabControl" SelectedIndex="1">
    <TabItem Name="Options">
        <TabItem.Header>
            <TextBlock>Options</TextBlock>
        </TabItem.Header>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <!-- ... -->
            </Grid.RowDefinitions>
            <Grid Grid.Row="0">
                <Grid.ColumnDefinitions>
                    <!-- ... -->
                </Grid.ColumnDefinitions>
                <Label Grid.Column="0"># Cables</Label>
                <xctk:IntegerUpDown Name="nCables" 
                                    Grid.Column="1" 
                                    Minimum="1" 
                                    Value="1"
                                    ValueChanged="nCablesChanged"/>
            </Grid>
            <Grid Grid.Row="1">
                <Grid.ColumnDefinitions>
                    <!-- ... -->
                </Grid.ColumnDefinitions>
                <Label Grid.Column="0"># Phases</Label>
                <xctk:IntegerUpDown Name="nPhases" 
                                    Grid.Column="1" 
                                    Minimum="1" 
                                    Value="4"
                                    ValueChanged="nPhasesChanged"/>
            </Grid>
            <l:NDataGrid Grid.Row="2"
                         x:Name="PhaseGrid"
                         ItemsSource="{Binding Phases, ElementName=Main}" 
                         LoadingRow="RowIndex"
                         CanUserAddRows="False"
                         CanUserDeleteRows="False"
                         CanUserReorderColumns="False"
                         CanUserSortColumns="False"
                         VerticalScrollBarVisibility="Hidden"
                         Block.TextAlignment="Center"/>
        </Grid>
    </TabItem>
</TabControl>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    ObservableCollection<NPhase> Phases;
    public static DependencyProperty PhasesProperty = DependencyProperty.Register("Phases", typeof(ICollectionView), typeof(MainWindow));
    public ICollectionView IPhasesCollection
    {
        get { return (ICollectionView)GetValue(PhasesProperty); }
        set { SetValue(PhasesProperty, value); }
    }
    /// <summary>Controls the number of cables to be created</summary>
    /// <param name="sender">(IntegerUpDown)nCables</param>
    /// <param name="e">not used</param>
    private void nCablesChanged(object sender, RoutedEventArgs e)
    {
        int n = tabControl.Items.Count - 1;
        var o = sender as IntegerUpDown;
        int v = (int)o.Value;
        if (v > n)
        {
            for (int i = n; i < v; i++)
            {
                TabItem tab = new TabItem();
                tab.Header = "C" + (i + 1);
                tab.Content = new NTab(Phases);
                tabControl.Items.Add(tab);
            }
        }
        else if (v < n)
        {
            for (int i = v; i < n; i++)
                tabControl.Items.RemoveAt(n);
        }
    }
    /// <summary>Modifies the DataGrid according to the number of phases desired</summary>
    /// <param name="sender">(IntegerUpDown)nPhases</param>
    /// <param name="e">not used</param>
    private void nPhasesChanged(object sender, RoutedEventArgs e)
    {
        //...
    }
    /// <summary>Sets up the row headers</summary>
    /// <param name="sender">not used</param>
    /// <param name="e">Row to be modified</param>
    private void RowIndex(object sender, DataGridRowEventArgs e)
    {
        e.Row.Header = (e.Row.GetIndex() + 1).ToString();
    }
    public MainWindow()
    {
        Phases = new ObservableCollection<NPhase>();
        Phases.Add(new NPhase(3, "Protensao Inicial"));
        Phases.Add(new NPhase(28, "Carga Movel"));
        Phases.Add(new NPhase(365, "1 Ano"));
        Phases.Add(new NPhase(18250, "Vida Util"));
        IPhasesCollection = CollectionViewSource.GetDefaultView(Phases); 
        InitializeComponent();
    }
}

NTab.xaml

<UserControl x:Class="WPF.NTab"
         x:Name="CableTab"
         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"
         xmlns:charting="clr-namespace:System.Windows.Forms.DataVisualization.Charting;assembly=System.Windows.Forms.DataVisualization"
         xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
         xmlns:l="clr-namespace:WPF"
         mc:Ignorable="d" >
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <!-- ... -->
    </Grid.RowDefinitions>
    <Grid Grid.Row="2">
        <Grid.ColumnDefinitions>
            <!-- ... -->
        </Grid.ColumnDefinitions>
        <Label Grid.Column="2">Pull Phase</Label>
        <ComboBox Grid.Column="3"
                  Name="Phase"
                  ItemsSource="{Binding Phases, ElementName=CableTab}"/>
    </Grid>
</Grid>
</UserControl>

NTab.xaml.cs

public partial class NTab : UserControl
{
    ObservableCollection<string> Phases;
    public static DependencyProperty PhasesProperty = DependencyProperty.Register("Phases", typeof(ICollectionView), typeof(NTab));
    public ICollectionView IPhasesCollection
    {
        get { return (ICollectionView)GetValue(PhasesProperty); }
        set { SetValue(PhasesProperty, value); }
    }
    /// <summary>Updates the tab's Phase list to match the list in the Options tab.</summary>
    /// <param name="source">(ObservableCollection&lt;NPhase&gt;</param>
    /// <param name="e">not used.</param>
    public void PhasesChanged(object source, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        var pC = source as ObservableCollection<NPhase>;
        Phases.Clear();
        for (int i = 0; i < pC.Count; i++)
            Phases.Add("" + (i + 1));
    }
    public NTab(ObservableCollection<NPhase> p)
    {
        InitializeComponent();
        Phases = new ObservableCollection<string>();
        IPhasesCollection = CollectionViewSource.GetDefaultView(Phases);
        PhasesChanged(p, new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Reset));
        p.CollectionChanged += PhasesChanged;
    }
}

您正在以错误的方式看待这个问题……当一个UI控件需要了解有关另一个UI控件的任何信息时,这在WPF中是一种罕见的情况。 处理数据更为常见。 借此,我的意思是您的NTab只需要知道Phase DataGrid中的数据 ,而不是控件中的数据。

实现此目的的最简单方法是为整个TabControl使用一个视图模型,该视图模型在各种TabItem共享其属性。 因此,与其尝试处理UI事件以使集合保持相同,不如对所有TabItem使用一个集合。 DataGrid ,您可以执行以下操作:

<DataGrid ItemsSource="{Binding YourCollection}" ... />

在每个其他TabItem ,您都可以这样做:

<ComboBox ItemsSource="{Binding YourCollection}" ... />

这样,一个TabItem集合的更新将自动反映在所有其他TabItem ,而您无需执行任何操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM