Control mit mehreren Items


  • Administrator

    /rant/ schrieb:

    Mit einem Custom Control kann man das sehr angenehm machen. Du leitest z.B. ein eigenes Control von ContentControl ab und definierst ein eigenes Template für die Darstellung. Dann bekommst du die Funktionalität fast gratis.

    Ich würde eher empfehlen von ItemsControl abzuleiten, wenn er "Items" darstellen möchte. Unter Umständen ist es nicht mal nötig, eine eigene Klasse zu erstellen, sondern man kann einfach entsprechende Templates ( ControlTemplate , DataTemplate , usw.) definieren, welche man dann dem ItemsControl im XAML übergibt.
    ItemsControl.Template
    ItemsControl.ItemsPanel
    ItemsControl.ItemTemplate

    Ebenfalls sollte man wohl ItemsPresenter erwähnen.

    Grüssli



  • Hallo Dravere.

    Unter Umständen ist es nicht mal nötig, eine eigene Klasse zu erstellen, sondern man kann einfach entsprechende Templates definieren

    Ja so hatte ich das ja bis jetzt. Ich habe ein UserControl verwendet. Darin habe ich ein ItemsControl angelegt und die Templates definiert.

    Das hat ja auch soweit funktioniert. Die Items selber liegen aber in einer ObservableCollection im ViewModel wogegen ich gebunden habe.

    In meiner View habe ich nun einfach das UserControl (CommandBar) angelegt und den DatenContext übergeben.

    <Views:CommandBarView DataContext="{Binding CommandBarViewModel}" DockPanel.Dock="Bottom" />
    

    Die Items werden nun im Code angelegt und der ObservableCollection hinzugefügt.

    Was ich nun aber gerne machen würde ist folgendes:

    <Views:CommandBarView  DockPanel.Dock="Bottom" >
                <CommandButtonItem Content="1" />
                <CommandButtonItem Content="2" />
                <CommandButtonItem Content="3" />
                <CommandButtonItem Content="4" />
    </ Views:CommandBarView>
    

    Wobei CommandButtonItem meine eigene Klasse ist.



  • Könnte mir da jemand nochmals helfen?



  • @Dravere: Natürlich wollte ich ItemsControl schreiben 🤡

    Parker schrieb:

    Könnte mir da jemand nochmals helfen?

    In etwa so?

    <Views:CommandBarView DockPanel.Dock="Bottom"> 
        <Views:CommandBarView.Items>
                <CommandButtonItem Content="1" /> 
                <CommandButtonItem Content="2" /> 
                <CommandButtonItem Content="3" /> 
                <CommandButtonItem Content="4" /> 
        </Views:CommandBarView.Items>
    </Views:CommandBarView>
    

    Oder wie oben beschrieben mit ContentPropertyAttribute. Oder verstehe ich dich falsch?

    MfG



  • public class CommandBarView : ItemsControl
    {
        static CommandBarView()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CommandBarView), new FrameworkPropertyMetadata(typeof(CommandBarView)));
        }
    
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is CommandButtonItem;
        }
    
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new CommandButtonItem();
        }
    }
    
    public class CommandButtonItem : ContentControl
    {
        static CommandButtonItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CommandButtonItem), new FrameworkPropertyMetadata(typeof(CommandButtonItem)));
        }
    }
    

    Das Aussehen definierst du dann über das Theming (Themes\Generic.xaml bzw spezifische Namen wie Aero.NormalColor.xaml usw, siehe MSDN).

    <Style TargetType="{x:Type Local:CommandBarView}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Local:CommandBarView}">
                    <!-- Entweder ein Panel zb StackPanel mit "IsItemsHost" oder den ItemsPresenter -->
                    <ItemsPresenter />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <Style TargetType="{x:Type Local:CommandButtonItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Local:CommandBarView}">
                    <!-- Entweder ein Panel zb StackPanel mit "IsItemsHost" oder den ItemsPresenter -->
                    <Button>
                        <ContentPresenter />
                    </Button>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    Nu kannst du es verwenden wie du es gerne hättest.

    <Views:CommandBarView DockPanel.Dock="Bottom"> 
        <Views:CommandButtonItem Content="1" /> 
        <Views:CommandButtonItem Content="2" /> 
        <Views:CommandButtonItem Content="3" /> 
        <Views:CommandButtonItem Content="4" /> 
    </Views:CommandBarView>
    

    Kannst die Liste auch Binden lassen (ItemsSource)

    Is doch Kinderkram.



  • Schön dass es für dich Kinderkram ist dann wird es ja ein leichtes für dich mich nochmal ein bischen zu unterstützen 🙂

    Danke zunächst mal für deine Hilfe.

    So sah mein UserControl bisher aus. Wie setzte ich das nun in der Generic.xaml um

    <ItemsControl Background="{StaticResource buttonBrush}" ItemsSource="{Binding Buttons}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Command="{Binding Command}"
                            Content="{Binding Content}"
                            IsEnabled="{Binding IsActivated}"
                            IsHitTestVisible="{Binding Converter={StaticResource O2BConverter}}"
                            Style="{StaticResource CommandButtonStyle}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

  • Administrator

    Parker schrieb:

    So sah mein UserControl bisher aus. Wie setzte ich das nun in der Generic.xaml um

    Also wenn dir das nicht klar ist, solltest du dich vielleicht nochmals etwas zu Templates, Styles und co einlesen gehen. Lies ruhig auch die Dokumentation zu den Methoden in der MSDN. David hat dir geradezu die Komplettlösung gegeben. Du musst fast nur noch ein wenig Copy&Paste betreiben. Ich dachte eigentlich, dass nach meiner Antwort schon alles klar sei.

    Ich würde dir somit raten, dass du es jetzt erst mal nochmals selber probierst und dich weiter dazu einliest. Und wenn du konkrete Fragen hast, kannst du mit diesen nochmals kommen. Aber es hat keinen Sinn, wenn wir das Problem für dich komplett lösen. So lernst du nix.

    Grüssli



  • Ok. Dann halt nochmals konkret gefragt.

    Zuerstmal ich würde mal sagen in Davids Lösung sind noch Copy&Paste Fehler.

    So wärs richtig:

    <Style TargetType="{x:Type Local:CommandBarView}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Local:CommandBarView}">
                    <!-- Entweder ein Panel zb StackPanel mit "IsItemsHost" oder den ItemsPresenter -->
                    <ItemsPresenter />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <Style TargetType="{x:Type Local:CommandButtonItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Local:CommandButtonItem}">
                    <Button>
                        <ContentPresenter />
                    </Button>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    Meine konkrette Frage:

    Wie binde ich denn nun meine Property IsActivated an IsEnabled

    Wenn ich das wie folgt mache

    ...
    <Button IsEnabled="{Binding IsActivated}" >
              <ContentPresenter />
    </Button>
    ...
    

    und IsActivated auf False setzte ist der Button immer noch aktiv.



  • Hajo, passiert, war hier im Forum getippt ^^
    Wie du schon gemerkt hast ist es ein Custom Control, kein UserControl.

    Wenn du das IsEnabled per Binding setzt, dann sucht das Control im DataContext des Containers (CommandButtonItem ist der Container wo gebundene Items im DataContext liegen, wenn du es direkt erstellst, ist DataContext leer).

    Du musst also im Container ein Property IsActivated machen und das auf den inneren Button durch reichen.

    <Style TargetType="{x:Type Local:CommandButtonItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Local:CommandButtonItem}">
                    <Button IsEnabled="{TemplateBinding IsActivated}">
                        <ContentPresenter />
                    </Button>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    public class CommandButtonItem : ContentControl
    {
        static CommandButtonItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CommandButtonItem), new FrameworkPropertyMetadata(typeof(CommandButtonItem)));
        }
    
        public bool IsActivated
        {
            get { return (bool)GetValue(IsActivatedProperty); }
            set { SetValue(IsActivatedProperty, value); }
        }
    
        public static readonly DependencyProperty IsActivatedProperty =
            DependencyProperty.Register("IsActivated", typeof(bool), typeof(ownerclass), new UIPropertyMetadata(0));
    }
    

    (propdp ist das Snippet)

    Sobald du das hast kannst du es einfach setzen und es geht auf den Inneren Button durch.
    Das selbe müsstest du auch noch mit Command, CommandParameter usw machen.

    <Views:CommandBarView> 
        <Views:CommandButtonItem Content="1" IsActivated="False" /> 
        <Views:CommandButtonItem Content="2" /> 
        <Views:CommandButtonItem Content="3" /> 
        <Views:CommandButtonItem Content="4" /> 
    </Views:CommandBarView>
    

    PS. du kannst auch einfach IsEnabled benutzen, hat das ContentControl schon und "erbt" sich auch nach unten durch, aber ich gehe davon aus das es nur ein Beispiel ist.



  • Danke!

    Hatte das Property IsActivated zwar in der Klasse drin aber halt nicht als Dependency Property. Und das TemplateBinding hatte ich auch nicht.


Anmelden zum Antworten