首页 文章

DataTemplate将ListBox绑定到ViewModel属性

提问于
浏览
0

我正在使用带有DataTemplate的ListBox .

<ListBox Grid.Row="1" Grid.ColumnSpan="3" Grid.RowSpan="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                                ItemsSource="{Binding Order.OrderLines}" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>

                            <TextBlock Grid.Column="0">Qty</TextBlock>
                            <TextBox Text="{Binding LineQty, Mode=TwoWay}" Grid.Column="1" />

                            <TextBlock Grid.Row="1" Grid.Column="0">Weight</TextBlock>
                            <TextBox Text="{Binding Path=LineWeight}" Grid.Row="1" Grid.Column="1" />

                            <TextBlock Grid.Column="0" Grid.Row="2">Pallet Weights</TextBlock>
                            <TextBox Text="{Binding PalletWeights}" Grid.Row="2" Grid.Column="1" />
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>

            </ListBox>

TextBox值正确绑定 . 问题是我的ViewModel上有一个名为“ViewMode”的属性,我将TextBox的IsEnabled属性绑定到App.xaml Style DataTrigger:

<Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding ViewMode}" Value="Add">
                    <Setter Property="BorderBrush" Value="White"></Setter>
                    <Setter Property="BorderThickness" Value="2,2,0,0"></Setter>
                    <Setter Property="BorderBrush" Value="Black"></Setter>
                    <Setter Property="BorderThickness" Value="0,0,2,2"></Setter>
                    <Setter Property="Background" Value="LightBlue"></Setter>
                    <Setter Property="Foreground" Value="Black"></Setter>
                    <Setter Property="FontWeight" Value="Bold"></Setter>
                    <Setter Property="IsEnabled" Value="true"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding ViewMode}" Value="Edit">
                    <Setter Property="BorderBrush" Value="White"></Setter>
                    <Setter Property="BorderThickness" Value="2,2,0,0"></Setter>
                    <Setter Property="BorderBrush" Value="Black"></Setter>
                    <Setter Property="BorderThickness" Value="0,0,2,2"></Setter>
                    <Setter Property="Background" Value="LightBlue"></Setter>
                    <Setter Property="Foreground" Value="Black"></Setter>
                    <Setter Property="FontWeight" Value="Bold"></Setter>
                    <Setter Property="IsEnabled" Value="true"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding ViewMode}" Value="View">
                    <Setter Property="IsEnabled" Value="false"></Setter>
                    <Setter Property="Foreground" Value="Gray"></Setter>
                </DataTrigger>
            </Style.Triggers>
            <Setter Property="Margin" Value="2" />
        </Style>

这适用于我的所有其他TextBox . 如何从DataTemplate中获取IsEnabled属性? ListBox的DataContext引用了ViewModel属性“Order”,所以我认为它应该能够看到ViewModel属性“ViewMode” .

谢谢,-Sid .

2 回答

  • 1

    在DataTemplate中,您无法直接从ViewModel访问属性(您不“继承”DataContext) . 假设您的ViewModel是整个视图的DataContext,您可以创建一个代理:

    class BindingProxy : Freezable
    {
    
        #region Freezable Members
    
        protected override Freezable CreateInstanceCore()
        {
            return new BindingProxy();
        }
    
        #endregion
    
        /// <summary>
        /// Saves the DataContext from the whole view
        /// </summary>
        public object DataContext
        {
            get { return (object)GetValue(DataContextProperty); }
            set { SetValue(DataContextProperty, value); }
        }
    
        public static readonly DependencyProperty DataContextProperty =
            DependencyProperty.Register("DataContext", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
    }
    

    然后,在您的XAML文件中,您需要引用BindingProxy所在的命名空间:

    <UserControl xmlns:utilities="clr-namespace:MyApp.NamespaceWhereBindingProxyIsLocated"
    ...
    

    稍后,为视图创建一个BindingProxy实例,并将其与视图的DataContext链接(请注意DataContext = 部分):

    <UserControl.Resources>
       <utilities:BindingProxy x:Key="proxy" DataContext="{Binding}"/>
    </UserControl.Resources>
    

    最后,您可以将它用作每个TextBox的DataContext:

    <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            ..
                            <TextBox Text="{Binding Path={TemplateBinding DataContext.LineQty}, Mode=TwoWay}" DataContext="{Binding Source={StaticResource proxy}, Path=DataContext}"/>
                            ..
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
    

    希望能帮助到你

  • 1

    您需要在Binding中使用 RelativeSource markup扩展名,以防您想要像这样前往Visual Tree -

    <DataTrigger Binding="{Binding DataContext.ViewMode,
                 RelativeSource={RelativeSource FindAncestor,
                                   AncestorType = UserControl}}" 
                 Value="Add">
    </DataTrigger>
    

    默认情况下, DataContextTextBox 将为 object of OrderLine ,您的属性 LineQty 驻留在哪里 . 因此,样式在 OrderLine 的对象中搜索 ViewMode 属性而不是ViewModel,因此您需要使用RelativeSource明确要求它在您的UserControl的 DataContext 中搜索它,这是您的 ViewModel .

相关问题