0

I'm having an issue where I have made a user control with two content collections in it. for simplicities sake we'll say its two items controls.

in the code behind I am exposing those itemCollections so that I can actually declare the content in another control.

for example

<!-- User Control xaml -->
<UserControl>
   <StackPanel Orientation="Horizontal" >
       <ItemsControl x:Name="_itemsControl1" />
       <ItemsControl x:Name="_itemsControl2" />
   </StackPanel>
</UserControl>


//in the codebehind for user control
public partial class TwoControls 
{
    public ItemCollection ItemsOne { get { return _itemsControl1.Items; }}
    public ItemCollection ItemsTwo { get { return _itemsControl2.Items; }}
}


<!-- Using the control in xaml later -->
<Custom:TwoControls>    
    <Custom:TwoControls.ItemsOne>
        <TextBox />
        <TextBox />
        <TextBox />
        <TextBox />
        <TextBox />
    </Custom:TwoControls.ItemsOne>
    <Custom:TwoControls.ItemsTwo>
        <Button />
        <Button />
        <Button />
        <Button />
        <Button />
    </Custom:TwoControls.ItemsTwo>
<Custom:TwoControls>

This actually works great with one small problem. As soon as I try to name any of the controls I get the following error.

<!-- Using the control in xaml later -->
<Custom:TwoControls>    
    <Custom:TwoControls.ItemsOne>
        <TextBox x:Name="txt"/>

Cannot set Name attribute value 'txt' on element 'TextBox'. 'TextBox' is under the scope of element 'TwoControls', which already had a name registered when it was defined in another scope.

If I didn't actually have to name the controls I wouldn't. We have some tools that run expecting certain content controls to be named so as part of the build process I need them to have names. Its also worth noting that I actually have a couple of events tied up in my TwoControls class, if I were to extract that to a data template I think I could make it work but I would have to work at it a bit more than currently.

Any input on why this is would be great.

tam
  • 1,583
  • 2
  • 13
  • 25
  • Does this answer your question? [How to create a WPF UserControl with NAMED content](https://stackoverflow.com/questions/751325/how-to-create-a-wpf-usercontrol-with-named-content) – StayOnTarget Apr 17 '20 at 20:51

1 Answers1

1

I do not want to sound blunt, but whenever I got this particular namescope problem, I remember I was doing things more the Winforms way than the WPF way. I use the Usercontrols more for pagelike controls than for containerlike controls.

A suggestion might be to create a custom control instead of a usercontrol.

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

      public ObservableCollection<UIElement> ItemsOne
      {
        get { return ( ObservableCollection<UIElement> )GetValue( ItemsOneProperty ); }
        set { SetValue( ItemsOneProperty , value ); }
      }
      public static readonly DependencyProperty ItemsOneProperty = DependencyProperty.Register( 
        "ItemsOne" , typeof( ObservableCollection<UIElement> ) , typeof( TwoControls ) , 
        new PropertyMetadata( new ObservableCollection<UIElement>( ) ) );

      public ObservableCollection<UIElement> ItemsTwo
      {
        get { return ( ObservableCollection<UIElement> )GetValue( ItemsTwoProperty ); }
        set { SetValue( ItemsTwoProperty , value ); }
      }
      public static readonly DependencyProperty ItemsTwoProperty = DependencyProperty.Register( 
        "ItemsTwo" , typeof( ObservableCollection<UIElement> ) , typeof( TwoControls ) , 
        new PropertyMetadata( new ObservableCollection<UIElement>( ) ) );
    }
      //The next in your ResourceDictionary
     <Style xmlns:local="clr-namespace:WPFApplication1" TargetType="{x:Type local:TwoControls}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type local:TwoControls}">
            <StackPanel Orientation="Horizontal">
              <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ItemsOne}"/>
              <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ItemsTwo}"/>
            </StackPanel>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    //The last in your xaml
    <Custom:TwoControls x:Name="twoControls1">
      <Custom:TwoControls.ItemsOne>
        <TextBox x:Name="Test1"/>
        <TextBox x:Name="Test2"/>
        <TextBox x:Name="Test3"/>
        <TextBox x:Name="Test4"/>
        <TextBox x:Name="Test5"/>
      </Custom:TwoControls.ItemsOne>
      <Custom:TwoControls.ItemsTwo>
        <Button x:Name="ButtonTest1"/>
        <Button x:Name="ButtonTest2"/>
        <Button x:Name="ButtonTest3"/>
        <Button x:Name="ButtonTest4"/>
        <Button x:Name="ButtonTest5"/>
      </Custom:TwoControls.ItemsTwo>
    </Custom:TwoControls>
Silvermind
  • 5,791
  • 2
  • 24
  • 44
  • nothing blunt there, this is essentially what I did end up doing. It was just as I said in my post, a little more work because I was handling quite a few events but it did work nicely once I was done. – tam Mar 10 '12 at 13:37