Laden...

[erledigt] WPF MVVM : TreeView

Erstellt von Ahrimaan vor 12 Jahren Letzter Beitrag vor 12 Jahren 3.025 Views
A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren
[erledigt] WPF MVVM : TreeView

Hallo zusammen,
nun muss ich auch mal mit neuem GUI zeugs arbeiten 😉

Ich will einen TreeView darstellen.


<TreeView ItemsSource="{Binding Items}">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}" > 
                    <Style.Triggers>
                        <Trigger Property="HasItems" Value="true">
                            <Setter Property="Focusable" Value="False"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding SubNodes}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="20"/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <CheckBox Grid.Column="0"/>
                        <TextBlock Text="{Binding Text}" Grid.Column="1"/>
                    </Grid>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>

Das klappt auch alles wunderbar nur :
Frage 1-> Wie kann ich zB den Items ein anderes template zuweisen ? (Also Items sollen keine Checkbox haben , die SubNodes aber schon)
Frage 2-> Ich wil lzwei Darstellungsformen : Einmal SubNodes MIT Checkbox und einmal ohne. Bisher habe ich durch Googlen nicht rausgefunden, wie ich zB zwei Templates dem Grid zuweisen kann

Frage 3. -> Wenn ein SubNode mit Checkbox angehakt wurde, sollen alle anderen SubItems Disabled werden. Bestimmt über Trigger nur wie ist mir gerade rätselhaft.

Kann mir jmd helfen ?

Grüße

1.552 Beiträge seit 2010
vor 12 Jahren

Hallo Ahrimaan,

hab zwar nie was mit TreeView gemacht, aber ich versuchs mal

Du hast sicherlich im ViewModel auch eine Tree-Structure. Dann lässt sich sicherlich herausfinden ob das Item ein, LeavType oder eben ein RootType ist. Dementsprechend wäre die ComboBox anzuzeigen oder zu verstecken.

Wie ich sehe hast du etwas ähnliches im Trigger schon gemacht..
Wenn HasItems=true, dann ist es ein RootType sonst ein LeaveType.

Gruß
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren

Hi,
ja ich kann den Trigger ansprechen und trotzdem weiß ich immer noch nicht wie ich dann eine Combobox einblende oder ausblende .....

Zu den anderen Fragen hast du nicht auch zufällig ne Antwort ? 😃

Grüße

109 Beiträge seit 2011
vor 12 Jahren

Hallo Ahrimaan,

mit dem TreeView habe ich auch noch nicht gearbeitet aber verschiedene Templates einem Grid zuweisen kannst du über DataGridTemplateColumn erreichen. Hier mal ein abgekürztes Beispiel von mir mit einem Template in der ersten Spalte und Text in der zweiten Spalte (ich hoffe mal das das auch dein Problem ist, ist nämlich für mich nicht so ganz ersichtlich)


        <DataGrid>
            <DataGrid.Columns>
                <DataGridTemplateColumn Width="Auto">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Height="20" Source="{Binding Image}"/>
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn
    				Width="*"
    				Binding="{Binding Message}" 
    				CanUserSort="False">
                    <DataGridTextColumn.Header>
                        <Label FontWeight="Bold" 
                               Background="#00350E0E" 
                               Content="Message" 
                               HorizontalContentAlignment="Center"/>
                    </DataGridTextColumn.Header>
                    <DataGridTextColumn.ElementStyle>
                        <Style TargetType="{x:Type TextBlock}">
                            <Setter Property="TextWrapping" Value="Wrap"/>
                            <Setter Property="TextAlignment" Value="Justify"/>
                            <Setter Property="Background" Value="{Binding Background}"/>
                        </Style>
                    </DataGridTextColumn.ElementStyle>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>

Edit: zu deiner ersten Frage: Wie gesagt kenne ich den WPF-Treeview und seine Möglichkeiten nicht aber dies läßt sich sicherlich über den DataTemplateSelector lösen. Wobei ich denke das diese Lösung ziemlich unperformant ist... aber wenn du keine andere Lösung findest könntest du es damit probieren.

Um Rekursion zu verstehen, muss man erst mal Rekursion verstehen, muss man erst mal Rekursion verstehen, ....

A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren

Hi,
danke für eure Tipps :
Ich habe es nun probiert anders zu lösen :

Ich will nun für gewisse Typen ein anderes aussehen machen.
Mir werden zwar nun die Rootnodes angezeigt aber nicht mehr die Subnodes.
Ich haben den Binding path auf SubNodes gesetzt.
Sicher übersehe ich was oder ?

<TreeView ItemsSource="{Binding Items}" Grid.Row="0">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}" > 
                    <Style.Triggers>
                        <Trigger Property="HasItems" Value="true">
                            <Setter Property="Focusable" Value="False"/>
                        </Trigger>
                        <Trigger Property="IsSelected" Value="true">
                            
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type Model:RootNode}">
                    <TextBlock Text="{Binding Text}"/>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type Model:SubNode}" ItemsSource="{Binding Path=SubNodes}">
                    <TextBlock Text="{Binding Text}"/>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
         </TreeView>

Grüße

A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren

Hallo,
hier die Antwort :

Ich erstelle ein Interface INode

Davon leite ich zwei Klassen ab : SubNode und SubNodewithCheckbox

<Window x:Class="MK.AgentWpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:MK.AgentWpf.ViewModel"
        xmlns:model="clr-namespace:MK.AgentWpf.Model"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:MainWindowModel x:Key="vm"/>
    </Window.Resources>
    <!--LayoutBegin-->
    <Grid DataContext="{Binding Source={StaticResource vm}}">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <TreeView ItemsSource="{Binding Items}">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}" >
                    <Style.Triggers>
                        <Trigger Property="HasItems" Value="true">
                            <Setter Property="Focusable" Value="False"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type model:RootNode}"
                              ItemsSource="{Binding Path=SubNodes}">
                    <Grid>
                        <TextBlock Text="{Binding Text}" />
                    </Grid>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type model:SubNodeItemWithCheckbox}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="20"/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <CheckBox Grid.Column="0" IsChecked="{Binding IsSelected, Mode=TwoWay}" IsEnabled="{Binding IsEnabled,Mode=TwoWay}"/>
                        <TextBlock Text="{Binding Text}" Grid.Column="1"/>
                    </Grid>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type model:SubNode}">
                          
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>


        <Button Grid.Row="1" Width="30">
            <Image Source="/Images/Sign001.ico"/>
        </Button>
    </Grid>
</Window>

Und das Model dazu :

public class SubNodeItemWithCheckbox:INode
    {
        public SubNodeItemWithCheckbox(RootNode parent)
        {
            _parent = parent;
        }

        private RootNode _parent;

        private bool _isEnabled;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set { _isEnabled = value;OnPropertyChanged(() => IsEnabled); }
        }

        private bool _isSelected;
        public bool IsSelected
        {
            get { return _isSelected; }
            set
            { 
                _isSelected = value;
                ChangeEnabledStatus();
                OnPropertyChanged(() => IsSelected); 
            }
        }

        private string _text;
        public string Text
        {
            get { return _text; }
            set { _text = value;OnPropertyChanged(() => Text); }
        }
        private void ChangeEnabledStatus()
        {
            foreach (INode subNode in _parent.SubNodes.Where(p => p.Text != _text))
            {
                subNode.IsEnabled = !_isSelected;
            }
        }

        #region OnPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged<T>(Expression<Func<T>> action)
        {
            var propertyName = GetPropertyName(action);
            OnPropertyChanged(propertyName);
        }

        private static string GetPropertyName<T>(Expression<Func<T>> action)
        {
            var expression = (MemberExpression)action.Body;
            var propertyName = expression.Member.Name;
            return propertyName;
        }

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }
        #endregion


        
    }

Zwei Sachen erreicht : Templates für die beiden klassen und bei Anklicken der Checkbox werden die anderen Checkboxen Disabled.

Grüße