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 样式 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>

这适用于我所有的其他文本框。如何让 IsEnabled 属性在 DataTemplate 中工作?ListBox 的 DataContext 引用了 ViewModel 属性“Order”,所以我认为它应该能够看到 ViewModel 属性“ViewMode”。

谢谢,-希德。

4

2 回答 2

1

Inside a DataTemplate, you don't get access to the properties from the ViewModel directly (you don't 'inherit' the DataContext). Assuming your ViewModel is the DataContext of the whole view, you can create a proxy:

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:

<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):

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

Finally, you can use it as the DataContext for each TextBox:

<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

于 2012-11-25T22:14:55.977 回答
1

You need to use RelativeSource markup extension in your Binding in case you want to travel up to the Visual Tree like this -

<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. 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.

于 2012-11-26T07:09:03.123 回答