Click here to Skip to main content
15,867,834 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi
I am creating a wpf application (my first one :) ) and I have a little problem.
In my application, I have a TreeView widt two columns, the first one with a string and the second one with a button. And the window only contains that control.

What I want is that TreeView fill the whole window and the last column must be always visible at the right side of the window, always with the same width.

Ex:
<-----  window width  ------>
+-----------------------+---+
           1              2


A new window width

XML
<---------  window width  ---------->
+-------------------------------+---+
               1                  2


What I ask is some directives to resolve this situation, XAML or code.

--- UPDATE ---

Here is the XAML code:

XML
<TreeView Name="trvFamilies">
 <TreeView.Resources>
  <HierarchicalDataTemplate DataType="{x:Type self:Family}" ItemsSource="{Binding Members}">
   <StackPanel Orientation="Horizontal">
     <TextBlock Text="{Binding Name}"/>
   </StackPanel>
  </HierarchicalDataTemplate>
  <DataTemplate DataType="{x:Type self:FamilyMember}">
   <StackPanel Orientation="Horizontal">
    <Grid>
     <Grid.ColumnDefinitions>
      <ColumnDefinition Width="230"></ColumnDefinition>
      <ColumnDefinition Width="20"></ColumnDefinition>
     </Grid.ColumnDefinitions>
     <TextBlock Text="{Binding Name}" Grid.Column="0"/>
     <Button Grid.Column="1" >C</Button>
    </Grid>
   </StackPanel>
  </DataTemplate>
 </TreeView.Resources>
 <TreeView.ItemContainerStyle>
  <Style TargetType="TreeViewItem">
   <Setter Property="VerticalContentAlignment" Value="Top" />
  </Style>
 </TreeView.ItemContainerStyle>
</TreeView>


I get this code from internet and I am adapted it to my situation. Obviously, there is a lot of things wrong with it, but my concern for now is just the two columns situation.

Best regards
Filipe Marques
Posted
Updated 3-Dec-14 11:25am
v2
Comments
Jan Bakker 3-Dec-14 3:30am    
Do the treeviewItems have 2 columns?
Filipe Marques 3-Dec-14 3:57am    
Hello Jan. Yes, the TreeViewItems have 2 columns. My only issue (I hope that be clear in my drawings :D ) is just about alignment. The width of the second column must be fixed and always docked to the right border of the window. The width of the first column is equal to window width minus the width of the second column. Beste regards, Filipe Marques
Jan Bakker 3-Dec-14 5:13am    
Do you use a template for your treeview, or are you just adding items in code behind. Could you show me that part of the code?
Filipe Marques 3-Dec-14 5:24am    
Sure, but I can not show you right now because I do not have the code with me. Thanks in advance, Filipe Marques
Filipe Marques 3-Dec-14 17:26pm    
Hi Jan, I updated my question

I've got something working.
The first column width must be "*".
The second must be "auto" (assuming your buttons have the same width).

The grid width must now be altered based on the available space left in the window.
We do this with a converter.

XML
<grid width="{Binding  ., UpdateSourceTrigger=PropertyChanged, Converter={local:GridWidthConverter}}"></grid>


XML
<Grid Margin="10">
        <TreeView Name="trvMenu">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:MenuItem}" ItemsSource="{Binding Items}">
                    <Border BorderBrush="Yellow" Padding="5" BorderThickness="1">
                        <Grid Width="{Binding  ., UpdateSourceTrigger=PropertyChanged, Converter={local:GridWidthConverter}}">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"></ColumnDefinition>
                                <ColumnDefinition Width="auto"></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <Border BorderBrush="AliceBlue" Padding="5" Grid.Column="0" BorderThickness="1">
                                <TextBlock Text="{Binding Title}" />
                            </Border>
                            <Border BorderBrush="Red" Padding="5" Grid.Column="1" BorderThickness="1">
                                <Button Width="80" Height="25" >C</Button>
                            </Border>
                        </Grid>
                    </Border>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>


The converter needs the level of the item so it can calculate the indent from the left of the screen.

So I added this to the class:

C#
public class MenuItem
        {
            public MenuItem()
            {
                this.Items = new ObservableCollection<MenuItem>();
            }

            public string Title { get; set; }
            public int level;

            public ObservableCollection<MenuItem> Items { get; set; }
        }

private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                MenuItem root = new MenuItem() { Title = "Menu", level=1 };
                MenuItem childItem1 = new MenuItem() { Title = "Child item #1", level=2 };
                childItem1.Items.Add(new MenuItem() { Title = "Child item #1.1", level=3 });
                childItem1.Items.Add(new MenuItem() { Title = "Child item #1.2",level=3 });
                root.Items.Add(childItem1);
                root.Items.Add(new MenuItem() { Title = "Child item #2", level=2 });
                trvMenu.Items.Add(root);
            }

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                trvMenu.BeginInit();
                trvMenu.EndInit();
            }



Now for the converter:

C#
class GridWidthConverter : System.Windows.Markup.MarkupExtension, IValueConverter
    {
        public GridWidthConverter()
        {
        }

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            MenuItem menuItem = (MenuItem)value;
            return (App.Current as App).TreeViewWindow.ActualWidth - (App.Current as App).TreeViewIndent - (App.Current as App).ExtraSpace - (menuItem.level * (App.Current as App).TreeViewIndent);
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return true;
        }
        private static GridWidthConverter instance;
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (instance == null)
                instance = new GridWidthConverter();
            return instance;
        }
    }


The converter returns: Window.ActualWidth - treeview indent - extraSpace (margins, padding, ....) - (level * treeview indent).

C#
public partial class App : Application
    {
        public Window TreeViewWindow;
        public double TreeViewIndent = 20;
        public double ExtraSpace = 50;
    }




Now all the buttons of all nodes will be aligned to the right side of the window.

It's kind of a hack.
So I would not go with a treeview, but use a listbox with a usercontrol if possible.

(I have no idea how to put a screenshot in the "answer")
 
Share this answer
 
Comments
Filipe Marques 5-Dec-14 15:31pm    
Hi Jan, I used your code and the variable TreeViewWindow is never initialized. Maybe there is something that I am missing. Best regards, Filipe Marques
Filipe Marques 12-Dec-14 22:45pm    
Hi Jan, finally I got to your code working. Thank you very much for your help :D Just one question, when I have the tree expanded and I resize the window, the tree is collapsed. There are any chances to avoid that? Best regards Filipe
Jan Bakker 15-Dec-14 2:01am    
The nodes do not now by themselfs if they are collapsed or expanded. You must provide that information in your data and by binding that data tell the nodes wich piece of data is used for collapsing and expanding.

So your data must contain for each item, for example: bool IsCollapsed.
(Or use some other name)

In your Treeview ControlTemplate you must bind that piece of information.
Jan Bakker 15-Dec-14 2:04am    
<pre> <Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsNodeExpanded}">
</Setter>
</Style>
</pre>


So, IsExpanded would be a better name ;)
Jan Bakker 15-Dec-14 2:12am    
Keep in mind that the wpf treeview is just the interface between the data and the user. The Treeview makes the data userfriendly to that user.

Never set selected or expanded or ... on the treeview itself. Always do that in your data.

Hi,

I just did a quick look at your xaml - didn't try.
But I think you have to define your first grid column Auto or with star Notation, something like this:

XML
<ColumnDefinition Width="230*"></ColumnDefinition>
      <ColumnDefinition Width="20"></ColumnDefinition>
 
Share this answer
 
Comments
Filipe Marques 5-Dec-14 15:29pm    
Hi, thanks for your answer but when I used the '*', the application crashes. Best regards, Filipe Marques
johannesnestler 6-Dec-14 8:21am    
this can't be the reason for your application to crash, I think you have another Problem... sry for not beeing very helpfull...
Filipe Marques 10-Dec-14 3:56am    
I am sorry for taking so long to answer you. Thanks anyway :) As I said, this is my first program using WPF (and my second ou third using c# :D) so there is a very high probability of something wrong. But I solve my problem (see my comment in Solution 4). I do not know if this the best approach, but it works. Best regards, Filipe Marques
Width must be set to "*" as shown below.

C#
<Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"></ColumnDefinition>
    <ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>


If you set it to "Auto" the left column will set its width according to its contents.
 
Share this answer
 
v2
Comments
Filipe Marques 5-Dec-14 15:31pm    
Hi, thank you for your answer but the result is the same as in johannesnestler solution, the application crashes. Best regards, Filipe Marques
Why do you use a button on every treeviewItem ?
Why not one button in the window and use treeviewItem IsSelected?
Or use a popup menu on right clicking a treeviewItem?
 
Share this answer
 
Comments
Filipe Marques 5-Dec-14 15:31pm    
I need a button on each item. I must reduce the interaction between the user and the application. Well, I search on internet and I found the solution: http://stackoverflow.com/questions/4969418/wpf-treeview-with-right-alignment-values It was what I wanted :) Thank you Jan for your help.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900