Visual studio like search - wpf

I want to implement Visual Studio like search. For now I want to make it search my UserControls, and on click it should open them in Tab.
I'm not searching for code, just for the right guidelines and the right terminology to try to implement this.
Thanks for any advice.
Example:

For searching in your UserControl collection I would use LINQ.
List<UserControl> results = (from UserControl control in list_of_usercontrols where (control.SomeParameter.ToLower().Contains(SearchParameter) || control.OtherParameter.ToLower().Contains(SearchParameter)) && nnn.IsEnabled select nnn).Distinct().ToList();
For displaying results I highly recommend ListView. I use it to show results in my WPF app, it's incredibly fast.
listView1.ItemsSource = results;
You can set ItemTemplate for your ListView.
<ListView Grid.Row="1" Name="listView1" BorderThickness="0" SelectionMode="Single" >
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label FontSize="15" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SomeProperty}"></TextBlock>
<TextBlock Text="{Binding OtherProperty}"></TextBlock>
<TextBlock Text="{Binding ThirdProperty}" ></TextBlock>
</StackPanel>
</Label>
<Label Content="{Binding FourthProperty}" Grid.Row="1" Padding="5,0,0,5"></Label>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Related

Using buttons in a DataGridColumn, WPF

I'm converting a Winforms app to WPF and run in to this error. In the winforms application the system loads buttons into a datagridview. As theres no datagridview in wpf, I've used datagrid. Sadly though, the things dont work. For some odd reason i cannot fix, i cant test what i thought of, i get a weird displayindex error. What i was wondering if someone can tell me either an alternative to what is used in the winforms app or tell me if what i have written works.
Winforms Code:
Dim btn As New DataGridViewButtonColumn()
dgBoorMachine.Columns.Add(btn)
btn.HeaderText = "del"
btn.Text = "X"
btn.Name = "del"
btn.UseColumnTextForButtonValue = True
dgBoorMachine.Columns("del").Width = 30
WPF Code:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="560"/>
<ColumnDefinition Width="425" />
<ColumnDefinition Width="560" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="156" />
<RowDefinition Height="55.2" />
<RowDefinition Height="89.6"/>
<RowDefinition Height="332.8"/>
<RowDefinition Height="217.6"/>
<RowDefinition Height="1" />
<RowDefinition Height="1" />
</Grid.RowDefinitions>
<DataGrid x:Name="dgSlijpMachine" Grid.Row="2" Grid.Column="1">
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btn1" Content="X" Click="btn1_Click"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid>
</Grid>
The error might be because you're missing the <DataGrid.Colums> tag
instead of
<DataGrid x:Name="dgSlijpMachine" Grid.Row="2" Grid.Column="1">
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btn1" Content="X" Click="btn1_Click"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid>
it should be
<DataGrid x:Name="dgSlijpMachine" Grid.Row="2" Grid.Column="1">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btn1" Content="X" Click="btn1_Click"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Now I don't know exactly what you want to achieve. What this will do, is add a column with a button to every row you add to your DataGrid and nothing else. If you actually want to populate your DataGrid with values, you should bind to the DataGrid's ItemsSource, eg.
<DataGrid x:Name="dgSlijpMachine" Grid.Row="2" Grid.Column="1" ItemsSource="{Binding MyItems}">
where MyItems is an ObservableCollection or similar type.

Creating a Table in XAML and populating it with an Array?

If I have a table like the one below:
<Grid VerticalAlignment="Top" HorizontalAlignment="Left" ShowGridLines="True" Width="250" Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock FontSize="20" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="0">2005 Products Shipped</TextBlock>
<TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="0">Quarter 1</TextBlock>
<TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="1">Quarter 2</TextBlock>
<TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="2">Quarter 3</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="0">50000</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="1">100000</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="2">150000</TextBlock>
<TextBlock FontSize="16" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="3">Total Units: 300000</TextBlock>
</Grid>
Would I be able to populate it in one go using an array.
For example, if I had an Array containing "Row 1", "Row 2" etc. thru 10 would I be able to populate the first column with those values?
I'm not sure I'm doing a great job of explaining. I know I could do each cell individually, but I want it to cycle through and do all at once?
Thanks
Firstly, consider just using a ListBox or ItemsControl, with a DataTemplate. Define the 2 header rows in a separate grid, and stack this one underneath. The catch with this approach is that you need to define fixed-width columns, since each row will be its own Grid (or actually StackPanel is more performant in this scenario):
<ItemsControl ItemsSource="{Binding TheArray}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Width="100" Text="{Binding Col1}" />
<TextBlock Width="100" Text="{Binding Col2}" />
<TextBlock Width="100" Text="{Binding Col3}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Secondly, if you need to use a true Grid, then one approach could be to define a Behavior on your Grid. This Behavior class would define an Items dependency property. The dependency property's "changed" handler could then create the TextBlocks (x of them for each cell where x is the number of columns), add them to the Grid, and assign the Grid.Row and Grid.Column properties (and even add the RowDefinitions if necessary).
<Grid>
<i:Interaction.Behaviors>
<my:GridItemsBehavior Items="{Binding TheArray}" />
</i:Interaction.Behaviors>
</Grid>
I wouldn't necessarily recommend the latter approach, because you lose a lot of the power of XAML by creating UI in code-behind.

Source versus DataContext in XAML

Which of these methods is best?
<Window.Resources>
<sys:Int16 x:Key="MyValue">123</sys:Int16>
</Window.Resources>
<StackPanel>
<!-- method 1 -->
<TextBlock Text="{Binding}" DataContext="{StaticResource MyValue}" />
<!-- method 2 -->
<TextBlock Text="{Binding, Source={StaticResource MyValue}}" />
</StackPanel>
As with many "which is better" questions. I would say that "it depends" on the context.
They both exist because they both can serve a purpose in different contexts. Given only what you have shown above, I would choose Example 2.
When you set the DataContext, however, all of its children will inherit that DataContext. So maybe instead you are using a Button. And within you Button, you want to jazz it up a bit and display the text four times each with a different color. As you can see below, I would then choose Example 1.
Example 1: (note the DataContext is on the button, and the TextBlocks don't need the Source like they do in Example 2)
<Button DataContext="{StaticResource MyValue}" Height="Auto" Width="Auto" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding}" Foreground="Red" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding}" Foreground="Blue" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding}" Foreground="Yellow"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding}" Foreground="Green" />
</Grid>
</Button>
Example 2:
<Button Height="Auto" Width="Auto" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding, Source={StaticResource MyValue}}" Foreground="Red" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding, Source={StaticResource MyValue}}" Foreground="Blue" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding, Source={StaticResource MyValue}}" Foreground="Yellow"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding, Source={StaticResource MyValue}}" Foreground="Green" />
</Grid>
</Button>
When you're binding to a simple object that only has one representation like an Int16 in your case, you're probably only going to bind and display that value once, and thus option 2 makes most sense.
A good rule of thumb... if you find yourself setting the 'Source' to the same thing more than one binding, you should probably just bind the DataContext of a common parent FrameworkElement.
I would say that if I had to choose between the two, I would go with method 2. DataContext is really more for Databinding an item to a more complex underlying object and eases the databinding of many data values.
Just out of curiosity, why are you doing it this way? Does your code change the value of MyValue at some point? Is there no better way for you to do it for some reason?
The DataContenxt DependencyProperty allows you to easily bind across all of proeprties for a DependencyObject.
The Source DependenceyProperty of a Binding allows you to point that specific binding to the source you want, regardless of the DataContext.
This becomes really helpful when you are doing more complex bindings for ListViews. For instance:
<Window.Resources>
<local:MyConverter x:Key="MyConverter" />
</Window.Resources>
<Grid>
<ComboBox ItemsSource="{Binding Source={StaticResource MyConverter}, Path=DisplayValues}" DataContenxt={Binding ElementName=lvwItems Path=SelectedItem} SelectedItem="{Binding Converter={StaticResource MyConverter}"/>
<ListView Name="lvwItems"......
The above example just shows off that I set the itemssource to a property in the 'MyConverter' called DisplayValues, the datacontext is what I am working with on that combobox though, which is handling the SelectedItem property of the ListView named 'lvwItems'.
Hope this helps.

WPF: ListBox itemtemplate tag navigation through items

I have a listbox that has a datatemplate which contains multiple text boxes. I want the user to be able to tab through all of the textboxes and then to the textboxes of the next list item without having to use CTRL+TAB.
Some XAML:
<DataTemplate x:Key="UsersDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="0">
<Label Content="Full Name" />
<TextBox Text="{Binding Path=FullName}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="0">
<Label Content="Address" />
<TextBox Text="{Binding Path=Address}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="1">
<Label Content="City" />
<TextBox Text="{Binding Path=City}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="0">
<Label Content="State" />
<TextBox Text="{Binding Path=State}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="1">
<Label Content="Zip" />
<TextBox Text="{Binding Path=Zip}" />
</StackPanel>
</Grid>
</DataTemplate>
<ListBox ItemTemplate="{DynamicResource UsersDataTemplate}"
ItemsSource="{Binding ElementName=MyUserControl, Path=Users}"
Width="914"
Margin="2,2,2,2" />
The idea is that the user may be presented with anywhere from 1 to 10 users in this listbox and they want to be able to tab into the listbox, editing/updating names & addresses and continue tabbing through all 10 users. The problem I am having is that when the user gets to the last textbox (zip) and hits tab, focus leaves the listbox completely.
I know this works with CTRL+TAB but this is unacceptable for the users experience. Is there a way to make the list box tab through its items with the TAB key instead of the CTRL+TAB key?
I tried using variations of KeyboardNavigation.TabNavigation, .ControlNavigation, etc without any luck, though I may be doing something wrong.
Any thoughts?
Hello I tested adding the following code to listbox declaration
<ListBox
KeyboardNavigation.TabNavigation="Continue"
works like a charm ;D

Do i have to build a ControlTemplate? Or is there an alternative?

I got a TreeView and want to display the Data nested (not hierarchically). The first level data is called TaskViewModel, the second level data is ArtifactViewModel. I want the ArtifactViewModel horizontal inside a GroupBox which represents TaskViewModel.
I tried different approaches, this is my last one:
<TreeView Name="tvTasks" ItemsSource="{Binding Tasks}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type vm:TaskViewModel}">
<GroupBox Header="{Binding Name, UpdateSourceTrigger=PropertyChanged}">
<StackPanel Orientation="Vertical">
<ListView ItemsSource="{Binding Children}"/>
<TextBlock Text="{Binding Description, UpdateSourceTrigger=PropertyChanged}" TextWrapping="Wrap"/>
</StackPanel>
</GroupBox>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type vm:ArtifactViewModel}">
<Border Background="{Binding Type,Converter={StaticResource Type2Background}}"
Margin="5" BorderBrush="Black" BorderThickness="2" CornerRadius="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
TextAlignment="Center" Background="Black" Foreground="White"
Opacity="0.75" Grid.Column="0" Grid.Row="1"/>
</Grid>
</Border>
</DataTemplate>
</TreeView.Resources>
</TreeView>
This looks pretty much like what i want, besides that ArtifactViewModels are shown vertical. And if i click on ArtifactViewModel the tvTasks.SelectedItem doesn't change, because the ListView handels this event. I know that this approach is not the cleverest, but it's just a try.
I looked at this article, but i don't see how to deal with the different objects i want to put in the TreeView. So ... how do i build such a UI?
The main issue you're running into here is that you're nesting multiple controls, each with their own selected items.
If you're planning on showing the data as nested but not hierarchically, don't bother using TreeView. If you want to have one item be selectable at any given point in time, use a ListBox instead.
Now the tricky part is playing around with how you want to lay the items out. Take a look at Bea Stollnitz's example here where she redraws a ListBox as a Canvas. You could do something similar where the ItemsPanelTemplate is a Canvas, and you calculate the x,y coordinates. Alternately, you could use a Grid, and determine the Grid.Row and Grid.Column values.

Resources