Свойство привязки между одноуровневыми пользовательскими элементами управления - PullRequest
0 голосов
/ 20 сентября 2018

У меня есть следующая проблема: у меня есть два разных пользовательских элемента управления внутри родительского элемента управления.Это 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 голосов
/ 20 сентября 2018

Возьмем эту простую модель представления с базовым классом, который реализует интерфейс 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>

Обратите внимание, что в этом простом примере элементы в пользовательском элементе управления XAML связываютсянепосредственно к экземпляру модели представления, который передается через их DataContext.Это означает, что UserControl знает модель представления (или хотя бы их свойства).Более общий подход заключается в объявлении свойств зависимостей в классе UserControl, которые связаны для просмотра свойств модели.Тогда UserControl будет независимым от какой-либо конкретной модели представления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...