.Net 4在ElementHost(MVVM)中绑定WPF Cotrol

问题描述:

Winforms应用程序中有WPF ElementHost。用户控件有一些文本和一个TreeView,它应该显示应用程序提供的可用命令树。.Net 4在ElementHost(MVVM)中绑定WPF Cotrol

我是新来的WPF(这是一个学习练习),所以我有一些问题绑定数据。

我创建了一个CommandTreeViewModel类来充当我的视图模型。它有一个FirstGeneration财产,这是一个IEnumerable(of CommandViewModel)。类别CommandViewModel又具有一些简单属性,描述Command包括Children属性(同样是IEnumerable(of CommandViewModel))。

我已经将我的WPF用户控件添加了一个Public Property ViewModel As CommandTreeViewModel,该WPF用户控件现在由我的winforms应用程序设置。

我不知道该怎么做是把我交给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 

正如你所看到的,我不属于R最后清楚我需要做什么,并一直试图从各种教程中破解一些代码。大部分只是WPF。

正确运行cotrol(我可以看到我的表单上的“Test”文本),但TreeView保持空白。没有错误被抛出。我假设这是因为我没有正确绑定数据。

最后,我还不清楚我的哪些属性需要DP?用户控件,ViewModel,模型儿童?我只是不清楚绑定是如何工作的。

这是很多代码解析,我没有在VB编码了一段时间,但我看到至少有几件事情。

我会建议你开始更简单一点。如果你真的刚刚开始,首先试着让一些简单的绑定,而不是一个多层次的命令树视图。尝试让一个平坦的数据网格去分层数据模板之前绑定,添加样式(带触发器!)等等。你一次介绍太多的概念恕我直言。

我不认为你需要在这里使用依赖属性,除非我失去了一些东西。当你想把一个用户控件拖放到另一个控件/窗口并且能够通过XAML/Databinding控制属性时,主要使用依赖属性。

它看起来像你试图通过依赖属性设置你的viewModel。相反,只要在代码隐藏的构造函数中设置DataContext属性 - 就像Me.DataContext = New CommandTreeViewModel(记住我的VB是生锈的:))。实际上,这可能是绑定不起作用的主要问题,因为View的DataContext没有设置。

最后,VS中的调试输出窗口应该包含任何数据绑定错误,这对于确定绑定失败的位置有很大的帮助。

+0

谢谢。 XAML几乎是逐字复制的,所以我意识到那里存在不必要的复杂性 - 我在调试时忘记考虑这一点。 'MyBase.DataContext'似乎是我需要的。我现在就玩。感谢一些非常好的提示。 – Basic 2011-04-14 02:47:40

+0

这对于一些错误的绑定命令,特别是'DataContext =“{Binding FirstGeneration}”''而不是'DataContext =“{Binding}”''调整工作。谢谢你的帮助! – Basic 2011-04-14 03:00:56

+0

没问题,很高兴你现在在正确的轨道上。 – 2011-04-14 03:14:38