Привязка .Net 4 к WPF Cotrol в ElementHost (MVVM) - PullRequest
0 голосов
/ 14 апреля 2011

У меня есть WPF ElementHost в приложении Winforms. Пользовательский элемент управления имеет некоторый текст и TreeView, который должен отображать дерево доступных команд, предоставляемых приложением.

Я новичок в WPF (это учебное упражнение), поэтому у меня возникли некоторые проблемы с привязкой данных.

Я создал CommandTreeViewModel класс, который будет действовать как моя модель представления. Он имеет свойство FirstGeneration, которое является IEnumerable(of CommandViewModel). Класс CommandViewModel, в свою очередь, обладает некоторыми простыми свойствами, описывающими Command, включая свойство Children (снова IEnumerable(of CommandViewModel)).

Я добавил Public Property ViewModel As CommandTreeViewModel в свой пользовательский элемент управления WPF, который сейчас установлен моим приложением winforms.

Чего я не знаю, как это сделать, так это взять те данные, которые были переданы мне в свойстве ViewModel, и связать их с TreeView. (И есть ли способ строго напечатать класс ViewModel моего XAML Binding в стиле MVC?)

Я включил нижеприведенный код на случай, если он понадобится.

Контроль пользователя

Public Class WPFCommandTree
    Implements INotifyPropertyChanged

    Public Property ViewModel As CommandTreeViewModel
        Get
            Return DirectCast(GetValue(ViewModelProperty), CommandTreeViewModel)
        End Get

        Set(ByVal value As CommandTreeViewModel)
            If Not value.Equals(DirectCast(GetValue(ViewModelProperty), CommandTreeViewModel)) Then
                SetValue(ViewModelProperty, value)
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("ViewModelProperty"))
            End If
        End Set
    End Property

    Public Shared ReadOnly ViewModelProperty As DependencyProperty = _
      DependencyProperty.Register("ViewModel",
      GetType(CommandTreeViewModel), GetType(Window),
      New FrameworkPropertyMetadata(Nothing))


    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class

XAML

<UserControl x:Class="WPFCommandTree"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="60" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock FontSize="30" HorizontalAlignment="Center" VerticalAlignment="Center">Test</TextBlock>
        <TreeView ItemsSource="{Binding FirstGeneration}"
                  VerticalAlignment="Stretch"
                  HorizontalAlignment="Stretch"
                  Grid.Row="1"
                  DataContext="{Binding}">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded"
                            Value="{Binding IsExpanded, Mode=TwoWay}" />
                    <Setter Property="IsSelected"
                            Value="{Binding IsSelected, Mode=TwoWay}" />
                    <Setter Property="FontWeight"
                            Value="Normal" />
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="FontWeight" Value="Bold" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</UserControl>

Просмотр моделей

Public Class CommandTreeViewModel
    Public Property RootCommand As CommandViewModel
    Public Property FirstGeneration As ReadOnlyCollection(Of CommandViewModel)

    Public Sub New(ByVal RootCommand As Command)
        _RootCommand = New CommandViewModel(RootCommand)
        _FirstGeneration = New ReadOnlyCollection(Of CommandViewModel)(New CommandViewModel() {_RootCommand})
    End Sub

    Public Sub New(ByVal RootCommand As CommandViewModel)
        Me.RootCommand = RootCommand
        Me.FirstGeneration = New ReadOnlyCollection(Of CommandViewModel)(New CommandViewModel() {_RootCommand})
    End Sub

    Public Sub New(ByVal RootCommands As IEnumerable(Of CommandViewModel))
        Me.RootCommand = RootCommands.First
        Me.FirstGeneration = New ReadOnlyCollection(Of CommandViewModel)(RootCommands.ToList)
    End Sub
End Class


Public Class CommandViewModel
    Implements INotifyPropertyChanged

    Public Property Command As Command
    Public Property Children As ReadOnlyCollection(Of CommandViewModel)
    Public Property Parent As CommandViewModel
    Public Property Name As String

    Private Property _IsSelected As Boolean
    Public Property IsSelected() As Boolean
        Get
            Return _isSelected
        End Get
        Set(ByVal value As Boolean)
            If value <> _isSelected Then
                _isSelected = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("IsSelected"))
            End If
        End Set
    End Property

    Private Property _IsExpanded As Boolean
    Public Property IsExpanded() As Boolean
        Get
            Return _IsExpanded
        End Get
        Set(ByVal value As Boolean)
            If value <> IsExpanded Then
                _IsExpanded = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("IsExpanded"))
                If _IsExpanded And _Parent IsNot Nothing Then
                    _Parent.IsExpanded = True
                End If
            End If
        End Set
    End Property

    Public Sub New(ByVal Command As Command)
        Me.New(Command, Nothing)
    End Sub


    Private Sub New(ByVal Command As Command, ByVal Parent As CommandViewModel)
        _Command = Command
        _Parent = Parent

        If Command.Children IsNot Nothing AndAlso Command.Children.Count > 0 Then
            _Children = New ReadOnlyCollection(Of CommandViewModel)(
             Command.Children.Select(Function(x) New CommandViewModel(x, Me)
            ).ToList)
        End If
    End Sub

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class

Как вы можете видеть, я не совсем понимаю, что мне нужно делать, и пытался взломать некоторый код из различных руководств. Большинство из них только WPF.

Выполнение вышеуказанного корректно загружает котрол (я вижу текст «Тест» в моей форме), но TreeView остается пустым. Ошибки не выбрасываются. Я предполагаю, что это потому, что я не правильно связал данные.

Наконец, мне также неясно, на каких из моих свойств должны быть DP? Пользовательский элемент управления, ViewModel, Model Children? Мне просто непонятно, как работает привязка.

1 Ответ

1 голос
/ 14 апреля 2011

Это много кода для анализа, и я некоторое время не кодировал VB, но я вижу по крайней мере несколько вещей.

Я бы порекомендовал вам начать немного проще.Если вы действительно только начинаете, начните с попытки связать что-то простое, а не древовидную структуру с несколькими уровнями команд.Попробуйте получить плоскую сетку данных для привязки, прежде чем переходить к шаблону иерархических данных, добавлять стили (с триггерами!) И т. Д. ИМХО вы вводите слишком много концепций одновременно.

Не думаю, что вам нужноиспользуя свойства зависимости вообще здесь, если я что-то упускаю.Свойства зависимостей в основном используются, когда вы хотите поместить пользовательский элемент управления в другой элемент управления / окно и иметь возможность управлять свойством через XAML / привязку данных.

Похоже, вы пытаетесь установить свой viewModel через свойство зависимостей,Вместо этого просто установите свойство DataContext в конструкторе вашего кода - что-то вроде Me.DataContext = New CommandTreeViewModel (помните, что мой VB ржавый :)).Вероятно, это ваша основная проблема, поскольку привязка не работает, поскольку DataContext представления не устанавливается.

Наконец, ваше окно вывода отладочной информации в VS должно содержать любые ошибки привязки данных, что очень помогает при вычислениигде привязка терпит неудачу.

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