2

抽象的:

我有两个UserControl名为ZoneZoneGroup。这些控件之一 ( ZoneGroup) 包括另一个 ( Zone) 的两个实例。他们都DataContext将根元素设置为this, 在Loaded事件处理程序中。

问题是DataContext内部控件(Zones)是在加载之前设置的(DataContextChanged事件发生在之前Loaded),这会导致 UI 出现一些故障。(内部Zone控件的初始状态是错误的。)如果我阻止它,一切正常(至少看起来是!)除了我遇到以下错误报告。(在输出窗口中)

public partial class Zone : UserControl
{
    ∙∙∙

    private void Zone_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        // Adding this if-clause solve UI problems but makes some binding errors!
        if (this.IsLoaded)
            brdRoot.DataContext = this;
    }
}

System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“ZoneGroup”(名称=“”)上找不到“ZoneBrush”属性。绑定表达式:路径=ZoneBrush;DataItem='ZoneGroup'(名称='');目标元素是 'brdRoot' (Name=''); 目标属性是“BorderBrush”(输入“Brush”)

细节:

有一个包含几个数据绑定的UserControl命名Zone,像这样..

<UserControl x:Class="MyApp.Zone"
    ∙∙∙&gt;
    <Border x:Name="brdRoot" BorderBrush="{Binding ZoneBrush}" BorderThickness="1">
        ∙∙∙
    </Border>
</UserControl>

所以,我将brdRoot数据上下文设置为

public partial class Zone : UserControl
{
    public Brush ZoneBrush
    {
        get { return (Brush)GetValue(ZoneBrushProperty); }
        set { SetValue(ZoneBrushProperty, value); }
    }

    ∙∙∙

    public Zone()
    {
        InitializeComponent();
    }

    private void Zone_Loaded(object sender, RoutedEventArgs e)
    {
        brdRoot.DataContext = this;
    }

    ∙∙∙
}

此外,还有一个UserControl有两个ContentPresenters 以包含和管理两个Zone控件。

<UserControl x:Class="MyApp.ZoneGroup"
    ∙∙∙&gt;
    <Border x:Name="brdRoot" BorderBrush="Gray" BorderThickness="1">
        <StackPanel Orientation="Horizontal">
            <ContentPresenter Content="{Binding MainZone}"
                              Margin="{Binding MainZonePadding}"/>
            <ContentPresenter Content="{Binding MemberZone}"/>
        </StackPanel>
    </Border>
</UserControl>

背后的代码是:

public partial class ZoneGroup : UserControl
{
    public Thickness MainZonePadding
    {
        get { return (Thickness)GetValue(MainZonePaddingProperty); }
        set { SetValue(MainZonePaddingProperty, value); }
    }

    public Zone MainZone
    {
        get { return (Zone)GetValue(MainZoneProperty); }
        set { SetValue(MainZoneProperty, value); }
    }

    public Zone MemberZone
    {
        get { return (Zone)GetValue(MemberZoneProperty); }
        set { SetValue(MemberZoneProperty, value); }
    }


    public ZoneGroup()
    {
        InitializeComponent();
    }

    private void ZoneGroup_Loaded(object sender, RoutedEventArgs e)
    {
        brdRoot.DataContext = this;
    }

    ∙∙∙
}

编辑 ►草图: 区域组控件中的两个区域控件。

我的应用程序按预期工作正常,但报告了一些 BindingExpression 错误。

4

2 回答 2

1

这不是一个直接的答案!

正如@HighCore 所说,我尝试使用 an而不是在我的用户控件ItemsControl中实现两个s。ContentPresenter为了清楚起见,我制作了一个新的简单应用程序,以便能够简单地描述它。所以请考虑一些新的假设:

这里又是两个UserControls;MyItem如下MyItemsControl

<UserControl x:Class="MyApp.MyItem"
             ∙∙∙&gt;
    <Grid x:Name="grdRoot">
        <Border BorderBrush="{Binding ItemBorderBrsuh}" BorderThickness="1">
            <TextBlock x:Name="txtColorIndicator"
                       Text="Item"
                       TextAlignment="Center"
                       Margin="5"/>
        </Border>
    </Grid>
</UserControl>

C#代码隐藏:

public partial class MyItem : UserControl
{
    #region ________________________________________  ItemBorderBrsuh

    public Brush ItemBorderBrsuh
    {
        get { return (Brush)GetValue(ItemBorderBrsuhProperty); }
        set { SetValue(ItemBorderBrsuhProperty, value); }
    }

    public static readonly DependencyProperty ItemBorderBrsuhProperty =
        DependencyProperty.Register("ItemBorderBrsuh",
                                    typeof(Brush),
                                    typeof(MyItem),
                                    new FrameworkPropertyMetadata(new SolidColorBrush(Colors.Black), FrameworkPropertyMetadataOptions.None, OnItemBorderBrsuhPropertyChanged));

    private static void OnItemBorderBrsuhPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        MyItem instance = sender as MyItem;

        if (instance != null && e.NewValue is SolidColorBrush)
            instance.txtColorIndicator.Text = (e.NewValue as SolidColorBrush).Color.ToString();
    }

    #endregion

    public MyItem()
    {
        InitializeComponent();

        grdRoot.DataContext = this;
    }
}

这就是 MyItemsControl。

<UserControl x:Class="MyApp.MyItemsControl"
    ∙∙∙&gt;
    <StackPanel>
        <TextBlock x:Name="txtHeader" Margin="0,0,0,5" TextAlignment="Center" Text="0 Item(s)"/>
        <Border BorderBrush="Gray" BorderThickness="1" Padding="5">
            <ItemsControl x:Name="itemsControl" ItemsSource="{Binding Items}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>

                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <local:MyItem />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </Border>
    </StackPanel>
</UserControl>

C# 代码隐藏:

public partial class MyItemsControl : UserControl
{
    private ObservableCollection<MyItem> _Items = new ObservableCollection<MyItem>();
    public ObservableCollection<MyItem> Items
    {
        get
        {
            return _Items;
        }
        set
        {
            _Items = value;
        }
    }

    private void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        txtHeader.Text = Items.Count + " Item(s)";
    }

    public MyItemsControl()
    {
        InitializeComponent();
        Items.CollectionChanged += Items_CollectionChanged;

        this.DataContext = this;
    }
}

以下是如何MyItemMyItemsControl.

<Grid>
    <local:MyItemsControl HorizontalAlignment="Center" VerticalAlignment="Center" Padding="5" BorderBrush="Black" BorderThickness="1">
        <local:MyItemsControl.Items>
            <local:MyItem ItemBorderBrsuh="Green" Margin="1"/>
            <local:MyItem ItemBorderBrsuh="Red" Margin="1"/>
            <local:MyItem ItemBorderBrsuh="Blue" Margin="1"/>
            <local:MyItem ItemBorderBrsuh="Orange" Margin="1"/>
        </local:MyItemsControl.Items>
    </local:MyItemsControl>
</Grid>

现在,s 没有问题BindingExpression,但还有一个重要的问题。如何更换

{
    grdRoot.DataContext = this;
}

{
    this.DataContext = this;
}

用真ViewModel

截屏:

我的项目控件


编辑: 我尝试实现 MVVM 模式,但存在一些问题。我在这里问了第一个。

于 2013-03-29T08:27:59.727 回答
1

UserControls你把所有这些和所有这些都过于复杂化了DependencyProperties。查看使用 0 行 C# 代码(仅 XAML)的示例:

<Window x:Class="MiscSamples.ItemsControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ItemsControl" Height="300" Width="300">
    <Window.Resources>

ItemsControl 的样式:

        <Style TargetType="ItemsControl" x:Key="ZoneItemsControlStyle">
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="Padding" Value="5"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ItemsControl">
                        <Border BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}"
                                Padding="5">
                            <DockPanel>
                                <TextBlock HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                           Text="{Binding Items.Count,RelativeSource={RelativeSource TemplatedParent}, StringFormat='{}{0} Item(s)'}"
                                           Foreground="{TemplateBinding Foreground}"
                                           DockPanel.Dock="Top"/>
                                <Border BorderBrush="{TemplateBinding BorderBrush}"
                                        BorderThickness="{TemplateBinding BorderThickness}"
                                        Padding="{TemplateBinding Padding}">
                                    <ItemsPresenter/>
                                </Border>
                            </DockPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal" IsItemsHost="True"/>
                    </ItemsPanelTemplate>
                </Setter.Value>
            </Setter>
        </Style>

画笔的数据模板:

        <DataTemplate DataType="{x:Type Brush}">
            <Border BorderBrush="{Binding}" Margin="1" BorderThickness="1" Padding="2,3,2,3">
                <TextBlock Text="{Binding}" TextAlignment="Center" Foreground="Black"/>
            </Border>
        </DataTemplate>

    </Window.Resources>

现在,它的用法:

    <Grid>
        <ItemsControl VerticalAlignment="Center" HorizontalAlignment="Center"
                      Style="{StaticResource ZoneItemsControlStyle}">
            <SolidColorBrush Color="Red"/>
            <SolidColorBrush Color="Green"/>
            <SolidColorBrush Color="Black"/>
            <SolidColorBrush Color="Blue"/>
        </ItemsControl>
    </Grid>
</Window>

结果:

在此处输入图像描述

看看我是如何利用DataTemplates来显示特定的自定义 UI 的Data Type?(在这种情况下,System.Windows.Media.Brush类)

我正在“使用画笔作为 ViewModels”。当然,您也可以创建自己的 ViewModel,然后DataTemplate为每种 VM 类型创建一个特定的。

另外,请参阅我如何使用TemplateBindingMarkupExtension 将内部的几个属性绑定到实例ControlTemplate中的相应值。ItemsControl

最后,看看你如何实际添加ANYkind 到ItemsControl.

另外,我必须提到我使用这种Style基于方法的方法是为了实现可重用性。您可以ItemsControl在应用程序的其他位置放置另一个并设置它Style="{StaticResource ZoneItemsControlStyle}",您就完成了。但是,如果您只打算使用一次,您可以将所有属性硬编码到ItemsControl.TemplateControlTemplate 中。

于 2013-04-03T17:49:21.690 回答