Как связать данные пользовательского UserControl - PullRequest
0 голосов
/ 21 января 2019

Итак, я просто настроил проект и добавил пользовательский элемент управления UserControl, который выглядит следующим образом.

<Grid>
        <ItemsControl ItemsSource="{Binding UserViewModel.Users}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <controls:UserCard/>
                        <TextBlock Text="{Binding Name}"/>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

        </ItemsControl>
    </Grid>

Как видите, я пытался связать свойство Text buti, но оно не связывается. Теперь может быть много причин, почему он так себя ведет, поэтому я постараюсь сузить его.

Я создал BaseViewModel, который будет содержать мои ViewModels, и выглядит это так.

public class BaseViewModel : ObservableObject
    {
        public UserViewModel UserViewModel { get; set; } = new UserViewModel();
    }

И тогда я настроил свою ViewModel следующим образом

public class UserViewModel : ObservableObject
    {
        public ObservableCollection<User> Users { get; set; } = new ObservableCollection<User>();

        public UserViewModel()
        {
            Users.Add(new User{Name = "Riley"});
            Users.Add(new User{Name = "Riley1"});
        }
    }

Просто, теперь у меня есть ObservableObject, который выглядит следующим образом и имеет дело с INPC

public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

А по моему MainView.xaml Я установил DataContext примерно так

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new BaseViewModel();
    }
}

То же самое для UserControl

И здесь я фактически добавляю UserControl, чтобы он отображался в MainWindow

<ItemsControl ItemsSource="{Binding UserViewModel.Users}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <controls:UserCard/>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>

    </ItemsControl>

Теперь проблема в том, что он не связывает данные, я хочу отобразить свойство Name из модели, но оно не отображается, и я не уверен, почему, если я пытаюсь связать его со свойством TextBlock в MainView напрямую работает нормально.

Я не уверен, почему он так себя ведет, и я хотел бы понять, почему. Нужно ли использовать DependencyProperties? Или это просто случай, когда я создаю новый экземпляр BaseViewModel? Где я ошибся?

1 Ответ

0 голосов
/ 21 января 2019

Ваш MainViewWindow содержит ItemsControl с привязкой ItemsSource="{Binding UserViewModel.Users}", где каждый элемент отображается с <controls:UserCard/>.Но ваш пользовательский элемент управления затем пытается снова привязаться к списку с помощью "{Binding UserViewModel.Users}".Почему вы пытаетесь отобразить список внутри другого списка?

Я подозреваю, что проблема здесь в том, что вы думаете, что ваш пользовательский UserControl DataContext все еще указывает на BaseViewModel, как и его родитель.Это не так.DataContext каждого элемента в ItemsControl указывает на его собственный связанный элемент в списке, то есть экземпляр типа User.

ОБНОВЛЕНО: Допустим, у вас есть модель основного вида со списком дочерних элементовпросмотреть модели, как это:

public class MainViewModel : ViewModelBase
{
    public MyChildViewModel[] MyItems { get; } =
    {
        new MyChildViewModel{MyCustomText = "Tom" },
        new MyChildViewModel{MyCustomText = "Dick" },
        new MyChildViewModel{MyCustomText = "Harry" }
    };
}

public class MyChildViewModel
{
    public string MyCustomText { get; set; }
}

И скажем, вы установили DataContext вашего MainWindow на экземпляр MainViewModel и добавили ListView:

<ListView ItemsSource="{Binding MyItems}" />

Если вы сделаете это, вы увидитеследующее:

enter image description here

Здесь происходит то, что ListView создает контейнер (типа ContentPresenter) для каждого из трех элементов в списке,и установка DataContext каждого из них для указания на его собственный экземпляр MyChildViewModel.По умолчанию ContentPresenter просто вызывает ToString () для своего DataContext, поэтому вы просто видите имя класса, на который он указывает.Если вы добавите оператор ToString() в свою модель MyChildViewModel следующим образом:

public override string ToString()
{
    return $"MyChildViewModel: {this.MyCustomText}";
}

... тогда вы увидите вместо этого:

enter image description here

Вы также можете полностью переопределить шаблон ListViewItem, и, поскольку он уже указывает на связанный с ним экземпляр MyChildViewModel, вы можете просто напрямую связать его свойства:

<ListView ItemsSource="{Binding MyItems}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <!-- One of these gets created for each element in the list -->
            <Border BorderBrush="Black" BorderThickness="1" Background="CornflowerBlue" CornerRadius="5" Padding="5">
                <TextBlock Text="{Binding MyCustomText}" Foreground="Yellow" />
            </Border>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

, который изменит отображение наэто:

enter image description here

Имеет смысл?

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