【问题标题】:.Net 4 Binding To WPF Cotrol in ElementHost (MVVM).Net 4 绑定到 ElementHost (MVVM) 中的 WPF 控件
【发布时间】:2011-04-13 21:51:22
【问题描述】:

我在 Winforms 应用程序中有一个 WPF ElementHost。用户控件有一些文本和一个TreeView,它应该显示应用程序提供的可用命令树。

我是 WPF 新手(这是一个学习练习),所以在绑定数据时遇到了一些问题。

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

我已将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

如您所见,我并不清楚我需要做什么,并且一直在尝试从各种教程中破解一些代码。大多数只是 WPF。

运行上述操作正确加载了控制(我可以在我的表单上看到“测试”文本),但 TreeView 保持空白。不会抛出任何错误。我假设这是因为我没有正确绑定数据。

最后,我还不清楚我的哪些房产需要成为 DP?用户控件、ViewModel、Model Children?我只是不清楚绑定是如何工作的。

【问题讨论】:

    标签: .net wpf data-binding .net-4.0 elementhost


    【解决方案1】:

    要解析的代码很多,我也有一段时间没用VB写代码了,但我至少看到了一些东西。

    我建议您从简单一点开始。如果您真的刚刚开始,请从尝试获取简单绑定的东西开始,而不是具有多级命令的树视图。在使用分层数据模板、添加样式(使用触发器!)等之前尝试绑定一个平面数据网格。恕我直言,您一次引入了太多概念。

    我认为你根本不需要在这里使用依赖属性,除非我遗漏了什么。依赖属性主要用于当您希望将用户控件拖放到另一个控件/窗口中并能够通过 XAML/数据绑定控制属性时使用。

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

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

    【讨论】:

    • 谢谢。 XAML 几乎是逐字复制的,所以我知道其中存在不必要的复杂性 - 我在调试时忘记考虑这一点。 MyBase.DataContext 似乎是我需要的。我现在就玩。感谢您提供一些非常好的建议。
    • 这与对一些错误绑定命令的调整一起起作用,特别是 DataContext="{Binding FirstGeneration}" 而不是 DataContext="{Binding}"。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 2010-12-15
    • 2011-05-28
    • 1970-01-01
    相关资源
    最近更新 更多