0

ElementHostWinformsアプリにWPFがあります。ユーザーコントロールにはいくつかのテキストがありTreeView、アプリによって提供される使用可能なコマンドのツリーを表示する必要があります。

私はWPF(これは学習演習です)を初めて使用するため、データのバインドに問題があります。

CommandTreeViewModelビューモデルとして機能するクラスを作成しました。であるFirstGenerationプロパティがありIEnumerable(of CommandViewModel)ます。次に、CommandViewModelクラスには、プロパティをCommand含めることを説明するいくつかの単純なプロパティがありChildrenます(ここでもIEnumerable(of CommandViewModel))。

Public Property ViewModel As CommandTreeViewModel今のところ、winformsアプリによって設定されるWPFユーザーコントロールにを追加しました。

方法がわからないのは、ViewModelプロパティで渡されたデータを取得し、それをTreeViewにバインドすることです。(そして、XAMLバインディングのViewModelクラスa-la 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、モデルの子?バインディングがどのように機能するのかよくわかりません。

4

1 に答える 1

1

解析するコードはたくさんあり、しばらくVBでコーディングしていませんが、少なくともいくつかのことがわかります。

もう少し簡単に始めることをお勧めします。本当に始めたばかりの場合は、複数のレベルのコマンドを含むツリービューではなく、バインドするのが簡単なものを取得することから始めます。階層データテンプレートを使用する前に、フラットなデータグリッドをバインドしてみてください。スタイルを追加します(トリガーを使用してください!)。一度に多くの概念を導入しているIMHO。

何かが足りない場合を除いて、ここで依存関係プロパティを使用する必要はまったくないと思います。依存関係プロパティは主に、ユーザーコントロールを別のコントロール/ウィンドウにドロップし、XAML/データバインディングを介してプロパティを制御する機能がある場合に使用されます。

依存関係プロパティを介してviewModelを設定しようとしているようです。代わりに、コードビハインドのコンストラクターでDataContextプロパティを設定するだけです。Me.DataContext= New CommandTreeViewModelのようになります(私のVBは錆びていることを忘れないでください:))。これは、ビューのDataContextが設定されていないため、実際にはバインディングが機能しないという主な問題である可能性があります。

最後に、VSのデバッグ出力ウィンドウにはデータバインディングエラーが含まれている必要があります。これは、バインディングが失敗している場所を特定するのに非常に役立ちます。

于 2011-04-14T01:37:06.707 に答える