C# 同级用户控件之间的绑定属性
我有以下问题:在父用户控件中有两个不同的用户控件。它们是C# 同级用户控件之间的绑定属性,c#,wpf,xaml,binding,C#,Wpf,Xaml,Binding,我有以下问题:在父用户控件中有两个不同的用户控件。它们是trainList,它包含列车对象列表和trainView,它是一个用户控件,显示列表中所选列车的详细信息 我希望与trainView共享trainList变量。 我现在得到的是: 父用户控件: 注意:列车类实现了INotifyPropertyChanged 如果我让它工作,我会将绑定应用到trainView用户控件(不确定这是否工作),而不是文本块 <UserControl> <customCon
trainList
,它包含列车对象列表和trainView
,它是一个用户控件,显示列表中所选列车的详细信息
我希望与trainView
共享trainList
变量。
我现在得到的是:
父用户控件:
注意:列车类实现了INotifyPropertyChanged
如果我让它工作,我会将绑定应用到trainView
用户控件(不确定这是否工作),而不是文本块
<UserControl>
<customControls:trainView x:Name="trainView" DataContext="{Binding ElementName=trainList, Path=SelectedTrain}"></customControls:trainView>
</UserControl>
然后,我将从trainView
的代码隐藏中访问该变量
(在此之后,我想与其父用户控件共享一个不同于trainView
的变量,但这可能是另一个问题)
我当前的问题是:这是以这种方式完成的还是我需要遵循另一种策略?以这个简单的视图模型为例,它有一个实现
INotifyPropertyChanged
接口的基类,以及一个Train、TrainViewModel和MainViewModel类
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetValue<T>(
ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (!Equals(storage, value))
{
storage = value;
OnPropertyChanged(propertyName);
}
}
}
public class Train : ViewModelBase
{
private string name;
public string Name
{
get { return name; }
set { SetValue(ref name, value); }
}
private string details;
public string Details
{
get { return details; }
set { SetValue(ref details, value); }
}
// more properties
}
public class TrainViewModel : ViewModelBase
{
public ObservableCollection<Train> Trains { get; }
= new ObservableCollection<Train>();
private Train selectedTrain;
public Train SelectedTrain
{
get { return selectedTrain; }
set { SetValue(ref selectedTrain, value); }
}
}
public class MainViewModel
{
public TrainViewModel TrainViewModel { get; } = new TrainViewModel();
}
TrainDetails控件看起来是这样的,当然,对于Train类的更多属性,有更多元素:
<UserControl ...>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Details}"/>
</StackPanel>
</UserControl>
父用户控件是这样的,我直接使用ListBox而不是TrainList控件:
<UserControl ...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding Trains}"
SelectedItem="{Binding SelectedTrain}"
DisplayMemberPath="Name"/>
<local:TrainDetailsControl Grid.Column="1" DataContext="{Binding SelectedTrain}"/>
</Grid>
</UserControl>
它将在主窗口中实例化,如下所示:
public MainWindow()
{
InitializeComponent();
var vm = new MainViewModel();
DataContext = vm;
vm.TrainViewModel.Trains.Add(new Train
{
Name = "Train 1",
Details = "Details of Train 1"
});
vm.TrainViewModel.Trains.Add(new Train
{
Name = "Train 2",
Details = "Details of Train 2"
});
}
<Grid>
<local:TrainControl DataContext="{Binding TrainViewModel}"/>
</Grid>
请注意,在这个简单的示例中,UserControls的XAML中的元素直接绑定到通过其DataContext传递的视图模型实例。这意味着UserControl知道视图模型(或者至少知道它们的属性)。更通用的方法是在UserControl类中声明依赖项属性,这些属性绑定到视图模型属性。用户控件将独立于任何特定的视图模型。首先,您在任何情况下都不应该拥有
DataContext=this
在UserControl的构造函数中,因为它会破坏其依赖项属性的任何典型的基于DataContext的绑定。其次,两个用户控件应该共享一个comman视图模型,该模型可能由外部用户控件提供。TrainList和TrainView(或其共内容)的属性都将绑定到公共视图模型,该模型将保存SelectedTrain属性和另一个包含所有列车列表的属性。@Clemens感谢您的回答。我是WPF新手,从未应用过MVVM模式。我不知道给我一个你提到的公共视图模型的示例实现是否太多。谢谢,这非常有用。但是,如果我想使用另一个UserControl而不是直接使用ListBox,我应该放什么?我尝试了
,但是列表没有填写,是空的(当我直接使用ListBox时,TrainsDetails控件工作得很好)。哦,好的。我想得太多了。只要
就行了。
<UserControl ...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding Trains}"
SelectedItem="{Binding SelectedTrain}"
DisplayMemberPath="Name"/>
<local:TrainDetailsControl Grid.Column="1" DataContext="{Binding SelectedTrain}"/>
</Grid>
</UserControl>
<Grid>
<local:TrainControl DataContext="{Binding TrainViewModel}"/>
</Grid>