简体   繁体   English

DataTemplate将ListBox绑定到ViewModel属性

[英]DataTemplate Binding for ListBox to ViewModel property

I'm using a ListBox with a DataTemplate. 我正在使用带有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>

The TextBox value is binding properly. TextBox值正确绑定。 The problem is I have a property on my ViewModel called "ViewMode" which I have the IsEnabled property of the TextBox bound to an App.xaml Style DataTrigger: 问题是我的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>

This works for all of my other TextBoxes. 这适用于我的所有其他TextBox。 How do I get the IsEnabled property to work from within the DataTemplate? 如何从DataTemplate中获取IsEnabled属性? The DataContext of the ListBox is referencing the ViewModel property "Order", so I would think it should be able to see the ViewModel property "ViewMode". ListBox的DataContext引用了ViewModel属性“Order”,所以我认为它应该能够看到ViewModel属性“ViewMode”。

Thanks, -Sid. 谢谢,-Sid。

Inside a DataTemplate, you don't get access to the properties from the ViewModel directly (you don't 'inherit' the DataContext). 在DataTemplate中,您无法直接从ViewModel访问属性(您不会'继承'DataContext)。 Assuming your ViewModel is the DataContext of the whole view, you can create a proxy: 假设您的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));
}

Then, in your XAML file, you need to reference the namespace where BindingProxy is located: 然后,在您的XAML文件中,您需要引用BindingProxy所在的命名空间:

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

Later, you create aan instance of BindingProxy for your view and link it with the view's DataContext (notice the DataContext={Binding} part): 稍后,为视图创建一个BindingProxy实例,并将其与视图的DataContext链接(请注意DataContext = {Binding}部分):

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

Finally, you can use it as the DataContext for each TextBox: 最后,您可以将它用作每个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>

Hope it helps 希望能帮助到你

You need to use RelativeSource markup extension in your Binding in case you want to travel up to the Visual Tree like this - 你需要在Binding中使用RelativeSource标记扩展,以防你想要像这样前往Visual Tree -

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

By default DataContext for your TextBox will be an object of OrderLine where is your property LineQty resides. 默认情况下, TextBox DataContext将是object of OrderLineobject of OrderLine LineQty所在的属性位于LineQty So, style is searching for ViewMode property in an object of OrderLine instead of your ViewModel so you need to use the RelativeSource to explicitly ask it to search it in DataContext of your UserControl which is your ViewModel . 因此,style在OrderLine的对象中搜索ViewMode属性而不是ViewModel,因此您需要使用RelativeSource明确要求它在UserControl的DataContext中搜索它,这是您的ViewModel

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM