简体   繁体   English

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

[英]Bind property between sibling user controls

I have the below problem: I have two different user controls inside a parent user control. 我有以下问题:父用户控件中有两个不同的用户控件。 These are trainList , wich holds a list of train objects and trainView , wich is an user control that shows details of the selected train in the list. 它们是trainList ,其中wich包含火车对象的列表, trainView是用户控件,用于显示列表中所选火车的详细信息。

My wish is to share a variable of trainList with trainView . 我的愿望是与trainView共享一个trainList变量。 What I have now is: 我现在所拥有的是:

Parent user control: 父级用户控件:

<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 class: 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);
        }
    }

Note: The Train class implements INotifyPropertyChanged . 注意: Train类实现INotifyPropertyChanged

If I got this to work, I'd apply the binding to the trainView user control (not sure if this would work) instead to the text block. 如果trainView起作用,则将绑定应用于trainView用户控件(不确定是否可行),而不是文本框。

    <UserControl>
        <customControls:trainView x:Name="trainView" DataContext="{Binding ElementName=trainList, Path=SelectedTrain}"></customControls:trainView>
    </UserControl>

And then, I would access that variable someway from the code-behind of trainView . 然后,我将从trainView的代码背后访问该变量。

(And after this, I would like to share a different variable from trainView with its parent user control, but maybe that's another question). (然后,我想与其父级用户控件共享不同于trainView变量,但这也许是另一个问题)。

My current question is: could this be done this way or would I need to follow another strategy? 我当前的问题是:这可以通过这种方式完成,还是需要采取其他策略?

Take this simple view model, with a base class that implements the INotifyPropertyChanged interface, and a Train, TrainViewModel and MainViewModel class. 以这个简单的视图模型为基础,该类具有实现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();
}

which may be initialized in the MainWindow's constructor like this: 可以在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"
    });
}

The TrainDetails controls would look like this, of course with more elements for more properties of the Train class: 当然,TrainDetails控件看起来像这样,当然,其中包含更多元素,用于Train类的更多属性:

<UserControl ...>
    <StackPanel>
        <TextBlock Text="{Binding Name}"/>
        <TextBlock Text="{Binding Details}"/>
    </StackPanel>
</UserControl>

and the parent UserControl like this, where I directly use a ListBox instead of a TrainList control: 和父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>

It would be instantiated in the MainWindow like this: 可以在MainWindow中实例化如下:

<Grid>
    <local:TrainControl DataContext="{Binding TrainViewModel}"/>
</Grid>

Note that in this simple example the elements in the UserControls' XAML bind directly to a view model instance that is passed via their DataContext. 请注意,在这个简单的示例中,UserControls的XAML中的元素直接绑定到通过其DataContext传递的视图模型实例。 This means that the UserControl know the view model (or at least their properties). 这意味着UserControl知道视图模型(或至少它们的属性)。 A more general approach is to declare dependency properties in the UserControl class, that are bound to view model properties. 一种更通用的方法是在UserControl类中声明依赖项属性,这些属性必须绑定到视图模型属性。 The UserControl would then be independent of any particular view model. 然后,UserControl将独立于任何特定的视图模型。

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

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