1

ControlTemplateカスタム コントロール用に を作成しましたMyControl

MyControl次のプロパティから派生しSystem.Windows.Controls.Control、定義しますpublic ObservableCollection<MyControl> Children{ get; protected set; }

ネストされた子コントロールを表示するには、で囲まれたItemsControl( ) を使用しています。子コントロールがない場合は、.StackPanelGroupBoxGroupBox

アプリケーションの起動時にすべて正常に動作します。Children プロパティに最初に少なくとも 1 つの要素が含まれていた場合、グループ ボックスと子コントロールが表示されます。それ以外の場合は非表示になります。

ユーザーが子コントロールを空のコレクションに追加すると、問題が発生します。のGroupBox可視性はまだ折りたたまれています。最後の子コントロールがコレクションから削除されると、同じ問題が発生します。はGroupBoxまだ表示されます。もう 1 つの症状は、HideEmptyEnumerationConverterコンバーターが呼び出されないことです。空でないコレクションへの子コントロールの追加/削除は、期待どおりに機能します。

次のバインディングの何が問題になっていますか? 私がバインドしているコレクションのタイプはObservableCollection.

<!-- Converter for hiding empty enumerations -->
<Common:HideEmptyEnumerationConverter x:Key="hideEmptyEnumerationConverter"/>
<!--- ... --->

<ControlTemplate TargetType="{x:Type MyControl}">
  <!-- ... other stuff that works ... -->
  <!-- Child components -->
  <GroupBox Header="Children"
            Visibility="{Binding RelativeSource={RelativeSource TemplatedParent},
              Path=Children, Converter={StaticResource hideEmptyEnumerationConverter}}">
    <ItemsControl ItemsSource="{TemplateBinding Children}"/>
  </GroupBox>
</ControlTemplate>

.

[ValueConversion(typeof (IEnumerable), typeof (Visibility))]
public class HideEmptyEnumerationConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int itemCount = ((IEnumerable) value).Cast<object>().Count();
        return itemCount == 0 ? Visibility.Collapsed : Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

もう 1 つの、より一般的な質問: 皆さんはどのようにバインディングをデバッグしていますか? これ(http://bea.stollnitz.com/blog/?p=52)を見つけましたが、それでも非常に難しいと思います。

助けや提案をいただければ幸いです。

4

2 に答える 2

6

問題は、Childrenプロパティ自体が変更されることはなく、コンテンツのみが変更されることです。プロパティ値は変更されないため、バインディングは再評価されません。あなたがする必要があるCountのは、コレクションのプロパティにバインドすることです。これを実現する最も簡単な方法はDataTrigger、テンプレートで a を使用することです。

<ControlTemplate TargetType="{x:Type MyControl}">
  <!-- ... other stuff that works ... -->
  <!-- Child components -->
  <GroupBox x:Name="gb" Header="Children">
    <ItemsControl ItemsSource="{TemplateBinding Children}"/>
  </GroupBox>
  <ControlTemplate.Triggers>
      <DataTrigger Binding="{Binding Path=Children.Count, RelativeSource={RelativeSource TemplatedParent}}"
                   Value="0">
        <Setter TargetName="gb" Property="Visibility" Value="Collapsed" />
      </DataTrigger>
  </ControlTemplate.Triggers>
</ControlTemplate>
于 2010-06-15T15:34:15.037 に答える
0

Children プロパティの項目数が変更されるたびに通知する必要があります。INotifyPropertyChanged インターフェイスを実装し、Children コレクションの CollectionChanged イベントに登録し、そこから PropertyChanged を発生させることで、これを行うことができます。

例:

public class MyControl : Control, INotifyPropertyChanged
{
    static MyControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
    }

    public ObservableCollection<UIElement> Children
    {
        get { return (ObservableCollection<UIElement>)GetValue(ChildrenProperty); }
        set { SetValue(ChildrenProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Children.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ChildrenProperty =
        DependencyProperty.Register("Children", typeof(ObservableCollection<UIElement>), typeof(MyControl), new UIPropertyMetadata(0));

    public MyControl()
    {
        Children = new ObservableCollection<UIElement>();
        Children.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Children_CollectionChanged);
    }

    void Children_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        RaisePropertyChanged("Children");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler temp = PropertyChanged;
        if (temp != null)
        {
            temp(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
于 2010-06-15T15:49:18.720 に答える