我遇到以下问题:父用户控件中有两个不同的用户控件。它们是trainList
,其中包含火车对象的列表,trainView
,其中是一个用户控件,用于显示列表中所选火车的详细信息。
我希望与trainList
共享一个变量trainView
。
我现在拥有的是:
父级用户控件:
<UserControl>
<UserControl>
<customControls:trainList x:Name="trainList"></customControls:trainList>
</UserControl>
<UserControl>
<customControls:trainView x:Name="trainView"></customControls:trainView>
</UserControl>
<TextBlock DataContext="{Binding ElementName=trainList, Path=SelectedTrain}" Text="{ Binding SelectedTrain.Id }">Test text</TextBlock>
</UserControl>
TrainList类:
public partial class TrainList : UserControl
{
public TrainList()
{
this.InitializeComponent();
this.DataContext = this;
}
public Train SelectedTrain { get; set; }
public void SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Debug.Print(this.SelectedTrain.Id);
}
}
注意:Train类实现INotifyPropertyChanged
。
如果我可以使用此绑定,请将该绑定应用于trainView
用户控件(不确定是否可以使用),而不是应用于文本块。
<UserControl>
<customControls:trainView x:Name="trainView" DataContext="{Binding ElementName=trainList, Path=SelectedTrain}"></customControls:trainView>
</UserControl>
然后,我将从trainView
的代码隐藏位置访问该变量。
(然后,我想与其父用户控件共享一个trainView
变量,但这可能是另一个问题)。
我当前的问题是:这可以通过这种方式完成,还是需要采取其他策略?
答案 0 :(得分:1)
使用一个简单的视图模型,该模型具有一个实现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();
}
可以在MainWindow的构造函数中初始化,如下所示:
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"
});
}
TrainDetails控件看起来像这样,当然,有更多元素可用于Train类的更多属性:
<UserControl ...>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Details}"/>
</StackPanel>
</UserControl>
和这样的父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>
它将在MainWindow中实例化如下:
<Grid>
<local:TrainControl DataContext="{Binding TrainViewModel}"/>
</Grid>
请注意,在此简单示例中,UserControls的XAML中的元素直接绑定到通过其DataContext传递的视图模型实例。这意味着UserControl知道视图模型(或至少它们的属性)。一种更通用的方法是在UserControl类中声明依赖项属性,这些属性必须绑定到视图模型属性。这样,UserControl将独立于任何特定的视图模型。