Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 同级用户控件之间的绑定属性_C#_Wpf_Xaml_Binding - Fatal编程技术网

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>