[英]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 ItemSource
是ObservableCollection
,我這樣做有什么被送到收集到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<NPhase></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.