在同级用户控件之间绑定属性

时间:2018-09-20 11:53:24

标签: c# wpf xaml binding

我遇到以下问题:父用户控件中有两个不同的用户控件。它们是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变量,但这可能是另一个问题)。

我当前的问题是:这可以通过这种方式完成,还是需要采取其他策略?

1 个答案:

答案 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将独立于任何特定的视图模型。