Create Telerik RadDataGrid in C# - c#

How can the XAML below coded in C#? I have to create a number of data grids depending on data coming back from a service call. The grids will be displayed side by side horizontally.
<telerikGrid:RadDataGrid x:Name="DataGrid1" GridLinesVisibility="Horizontal" AlternateRowBackground="CornflowerBlue" GridLinesThickness="3">
<telerikGrid:RadDataGrid.Columns>
<telerikGrid:DataGridTemplateColumn Header="Country">
<telerikGrid:DataGridTemplateColumn.CellContentTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding CountryName}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<HyperlinkButton Content="Some link"></HyperlinkButton>
<Button Content="Button"></Button>
</StackPanel>
</DataTemplate>
</telerikGrid:DataGridTemplateColumn.CellContentTemplate>
</telerikGrid:DataGridTemplateColumn>
</telerikGrid:RadDataGrid.Columns>
</telerikGrid:RadDataGrid>
<telerikGrid:RadDataGrid x:Name="DataGrid2">
<telerikGrid:RadDataGrid.Columns>
<telerikGrid:DataGridTextColumn PropertyName="CapitalName" Header="Capital Name">
<telerikGrid:DataGridTextColumn.HeaderStyle>
<Style TargetType="gridPrimitives:DataGridColumnHeader">
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="FontSize" Value="16"/>
</Style>
</telerikGrid:DataGridTextColumn.HeaderStyle>
</telerikGrid:DataGridTextColumn>
</telerikGrid:RadDataGrid.Columns>
</telerikGrid:RadDataGrid>
<telerikGrid:RadDataGrid x:Name="DataGrid3">
<telerikGrid:RadDataGrid.Columns>
<telerikGrid:DataGridTextColumn PropertyName="CapitalName" Header="Capital Name">
<telerikGrid:DataGridTextColumn.HeaderStyle>
<Style TargetType="gridPrimitives:DataGridColumnHeader">
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</telerikGrid:DataGridTextColumn.HeaderStyle>
</telerikGrid:DataGridTextColumn>
</telerikGrid:RadDataGrid.Columns>
</telerikGrid:RadDataGrid>

I would suggest that you are trying to solve your problem in the wrong way. Why create multiple RadDataGrid instances which only have 1 column each?
Wouldn't one grid, with multiple columns be a better fit? It would certainly seem so from the data names you've supplied.
Then you can bind the Visibility property of each column to some ViewModel property which can show/hide columns according to the data you have available.

Related

C# WPF The global style not working in some parts of the code [duplicate]

I am trying to learn something about WPF and I am quite amazed by its flexibility.
However, I have hit a problem with Styles and DataTemplates, which is little bit confusing.
I have defined below test page to play around a bit with styles etc and found that the Styles defined in <Page.Resources> for Border and TextBlock are not applied in the DataTemplate, but Style for ProgressBar defined in exactly the same way is applied.
Source code (I just use Kaxaml and XamlPadX to view the result)
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="Background" Value="SkyBlue"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="CornerRadius" Value="5"/>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontWeight" Value="Bold"/>
</Style>
<Style TargetType="{x:Type ProgressBar}">
<Setter Property="Height" Value="10"/>
<Setter Property="Width" Value="100"/>
<Setter Property="Foreground" Value="Red"/>
</Style>
<XmlDataProvider x:Key="TestData" XPath="/TestData">
<x:XData>
<TestData xmlns="">
<TestElement>
<Name>Item 1</Name>
<Value>25</Value>
</TestElement>
<TestElement>
<Name>Item 2</Name>
<Value>50</Value>
</TestElement>
</TestData>
</x:XData>
</XmlDataProvider>
<HierarchicalDataTemplate DataType="TestElement">
<Border Height="45" Width="120" Margin="5,5">
<StackPanel Orientation="Vertical" Margin="5,5" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center" Text="{Binding XPath=Name}"/>
<ProgressBar Value="{Binding XPath=Value}"/>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
</Page.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<Border Height="45" Width="120" Margin="5,5">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center" Text="Item 1"/>
<ProgressBar Value="25"/>
</StackPanel>
</Border>
<Border Height="45" Width="120" Margin="5,5">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center" Text="Item 2"/>
<ProgressBar Value="50"/>
</StackPanel>
</Border>
</StackPanel>
<ListBox Margin="10,10" Width="140" ItemsSource="{Binding Source={StaticResource TestData}, XPath=TestElement}"/>
</StackPanel>
</Page>
I suspect it has something to do with default styles etc, but more puzzling is why some Styles are applied and some not. I cannot find an easy explanation for above anywhere and thus would like to ask if someone would be kind enough to explain this behaviour in lamens' terms with possible links to technical description, i.e. to MSDN or so.
Thanks in advance for you support!
I discovered a simple workaround for this. For any elements that are not able to search outside the data template encapsulation boundary (i.e. are not being implicitly styled), you can just declare an empty style within the data template for that element type and use the BasedOn attribute of the style to find the correct implicit style outside the data template to apply.
In the example below, the TextBox is able to search outside the data template encapsulation boundary (because it inherits from Control?), but the TextBlock is not able to, so I declare the empty style for it which can search outside the data template.
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}" />
</DataTemplate.Resources>
<DockPanel>
<TextBlock Text="{Binding Name}" />
<TextBox Text="{Binding Value}" />
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
This is actually by design. Elements that do not derive from Control will not pick up implicit Styles, unless they are in the application resources.
This link explains this in more detail, or you can view the Connent bug report.
I've looked into this also, and I personally think it's a bug. I've noticed that the style is set if you name your styles like so:
<Style x:Key="BorderStyle" TargetType="{x:Type Border}">
etc...
and explicitly set your DataTemplate to use those styles:
<HierarchicalDataTemplate DataTemplate="TestElement">
<Border Height="45" Width="120" Margin="5,5", Style="{StaticResource BorderStyle}">
I think that it's possible that for DataTemplates (and maybe ControlTemplates), they default to having a null style, unless you explicitly set them.
That to me is not meant to happen - it's not a logical way of WPF working...
This is because ListBox is a logical parent of your datatemplate items, now remember, all properties those are "inheritable" like font, forecolor etc, are derived from the logical parent and ListBox already overrides it in its own default style, thats why this will not work. However in this case, you can use named styles as Mr. Dave has suggested, but I think if it does not work then this is a known problem in case of List Box etc, you can refere to my question here, i had similar problem in listbox, and the answers in my question are in more detail.

In WPF, is it possible to represent the same ViewModel with different Views, based on some condition?

I am making a TreeView with multiple levels of information being displayed. What I am hoping to achieve, is to show a different view when the sub-tree is expanded and closed. So, when just looking at the list, I want to make a view which shows a brief status overview of my more detailed view that would be visible if you expanded that item in the list.
I know I could just create 2 viewmodels implementing the same Interface, and based on a boolean IsExpanded, I could set the ActiveViewModel to one or the other, but I was just curious if I could just have the one viewmodel and change its view based on that boolean instead to save memory.
-OR-
Alternatively, should I just put 2 StackPanels into the same View, and then bind a visibility to be inverse of each other, so only one can be shown at a time?
-CODE-
Here is my current code (Private information removed / generic representation):
Xaml:
<UserControl.Resources>
<Style x:Key="TreeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Padding" Value="5"></Setter>
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{StaticResource Univers57}"/>
<Setter Property="FontSize" Value="20" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</UserControl.Resources>
<TreeView x:Name="TreeView"
HorizontalAlignment="Stretch"
ItemsSource="{Binding ItemViewModels}"
ItemContainerStyle="{StaticResource TreeViewItemStyle}">
<TreeView.Resources>
<HierarchicalDataTemplate
DataType="{x:Type viewModel:ItemViewModel}" ItemsSource="{Binding Tasks}">
<StackPanel Orientation="Horizontal" Visibility="{Binding IsVisible}>
<Image Source="../../Images/Image.png" Height="24" Width="24"/>
<TextBlock Text="{Binding Item.Name}" />
<Button Style="{StaticResource ButtonStyle}">Dispatch</Button>
</StackPanel>
<StackPanel Orientation="Horizontal" Visibility="{Binding IsOtherVisible}>
<Image Source="../../Images/Image2.png" Height="24" Width="24"/>
<TextBlock Text="{Binding Item.Name}" />
<Button Style="{StaticResource ButtonStyle}">Dispatch</Button>
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate
DataType="{x:Type viewModel:TaskViewModel}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Task.Name}" Width="200"/>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
Both the ItemViewModel and TaskViewModel inherit from 'TreeViewModel' which implements INotifyPropertyChanged, and has IsExpanded and IsSelected.
IsVisible on the StackPanel Binding should be set based on IsExpanded's value. (It only shows up once you expand the item. So, one stackpanel or the other should show up).
I have just had a play with the WPF Visual Tree tools in VS2015 and it looks like the IsExpanded isnt being changed when I expand/collapse the tree items. It only sets a value during creation of the viewmodels, after that it will never change - even though they physically open and close when running the program.
Have managed to find a solution.
Firstly, needed to set 2 Way Binding on the binding to IsExpanded.
Secondly, I have overridden / hidden IsExpanded by declaring it as new in the derived class.
Now when set() gets called on IsExpanded, I can make a change to the IsVisible and IsOtherVisible before sending OnPropertyChange(); Now that I can change the IsVisible's, they can fire their own OnPropertyChange() and all is good in the world again.

Datagrid and Listview with same itemssource

I have a WPF application with a DataGrid and ListView that share the same ObservableCollection ItemsSource. When the DataGrid's CanUserAddRows property is True it causes the ListView to display the extra item that the DataGrid uses to add new rows.
How can I get the extra row from the DataGrid to not show in the ListView?
I tried using a trigger on the ListView's DataTemplate and checking if the items Id was empty or 0
`<ListView.ItemTemplate>
<DataTemplate>
<Label Margin="-2,0,0,0" Name="CategoryLabel" >
<TextBlock TextWrapping="Wrap" Text="{Binding categoryName}" Height="46"></TextBlock>
</Label>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding categoryId}" Value="0" > <!-- also tried Value="" -->
<Setter TargetName="CategoryLabel" Property="Visibility" Value="Hidden" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>`
I just posted an answer to a problem of changing the template using a data template selector
Change View with its ViewModel based on a ViewModel Property
Possibly just because I have recently looked at this but I wonder if it might be possible to use the same technique here.
Have one template for where the category has a value,then another blank template for values without a category. The important part is you do the test in code rather than XAML so easier to inspect.
You can solve your problem without any modification of your ViewModel or code behind. You can do well without explicitly defining CollectionView's of any kind. Just add to your view's XAML one more (or only) DataTrigger that triggers on the NewItemPlaceholder item of the default view of ListView ItemsSource's collection. Have this trigger to set the UIElement.Visibility attached property to "Hidden". Place it within ItemContainerStyle style triggers. Like this:
<ListView
ItemsSource="{Binding ...}"
>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
...
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding}"
Value="{x:Static CollectionView.NewItemPlaceholder}">
<Setter Property="UIElement.Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="..." Value="{Binding ...}" />
...
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Label Margin="..." Name="...">
<TextBlock TextWrapping="Wrap"
Text="{Binding ...}" />
</Label>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>

Interactive Grid WPF

I am currently working in C# WPF 4.5 and am attempting to create an interactive grid. Given the grid cell square size (width = height), number of columns and number of rows, I'd like to dynamically generate the grid on the screen.
For the generated grid, I'd like the grid lines to be visible. I'm thinking this could be emulated by just drawing a border within each cell if nothing else. On top of all this, I need an event to be able to determine what cell the user clicks on (i.e., on click return gird column and row) with the ability to select one or more cell at a time.
Any help or ideas on how I could create something like this or is there a better way to go about it? Thanks in advance!
Edit:
So here's some progress I've made:
Created a custom checkbox:
<Style x:Key="styleCustomCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid x:Name="Background" Background="Transparent">
<Rectangle x:Name="fillCheckBox"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="fillCheckBox" Property="Fill" Value="Transparent"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="fillCheckBox" Property="Fill" Value="Red"/>
<Setter TargetName="fillCheckBox" Property="Opacity" Value=".3"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And then just populate a grid with the custom checkboxes of that style:
<CheckBox Grid.Column="1" Grid.Row="1" Style="{StaticResource styleCustomCheckBox}" />
So now I'd like to map each of checkboxes within the grid where I can gather whether the checkbox is checked or not and what grid row and column it is in, how would I go about this?
I would use an ItemsControl with its ItemsPanelTemplate set to a UniformGrid, and it's ItemTemplate set to your CheckBox
It would be easiest if you could bind your ItemsControl.ItemsSource to a collection of data objects in your code behind. For example:
<ItemsControl ItemsSource="{Binding MyCollection}">
<!-- ItemsPanelTemplate -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="5" Columns="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- ItemTemplate -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="1">
<CheckBox Style="{StaticResource styleCustomCheckBox}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you needed to specify the Row or Column index of the checked item, you could add that to your data item and use a regular Grid instead of a UniformGrid, and apply an ItemContainerStyle like this:
<!-- ItemContainerStyle -->
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding ColumnIndex}" />
<Setter Property="Grid.Row" Value="{Binding RowIndex}" />
</Style>
</ItemsControl.ItemContainerStyle>
To determine the item clicked on, that depends on how you structure your data object and what you actually want to do in your click.
If you wanted the data item behind the square, you could just use the DataContext, such as
void MyCheckBox_Clicked(object sender, EventArgs e)
{
var selectedItem = ((CheckBox)sender).DataContext;
}
Or if you had something like a data item with an IsChecked property like this:
<CheckBox IsChecked="{Binding IsChecked}"
Style="{StaticResource styleCustomCheckBox}" />
You could easily attach an event to the PropertyChanged event for the data item's IsChecked property, and run some code there.
As a third alternative you could use a Button for your ItemTemplate and pass the selected item as the CommandParameter
<Border BorderBrush="Red" BorderThickness="1">
<Button CommandParameter="{Binding }" ... />
</Border>
I can't give you an definite answer because I don't know your code base and what you're trying to do, but I hope this gives you enough information to give you a rough start and point you in the right direction for your situation.

How to get the Binding element of a collection inside an item template in WPF?

I have a custom control RadCoverFlow that takes a collection of Image as an itemsSource.
<StackPanel Orientation="Vertical" Background="Black">
<telerik:RadCoverFlow x:Name="coverFlow"
ItemsSource="{Binding ViewImages, Mode=OneWay}"
ItemTemplate="{StaticResource ImageTemplate}"
</telerik:RadCoverFlow>
</StackPanel>
I want to define the widh, the height and a couple of other properties of the Images using a data template. My problem is that in the Data Template, I need to specify a source for each images, but that source is already specified in code.
<DataTemplate x:Key="ImageTemplate">
<Image Source="" Width="100" Height="100" Stretch="Uniform" telerik:RadCoverFlow.EnableLoadNotification="True" />
</DataTemplate>
How can I not re-specify the Source, or bind the source to the Source like {Binding ViewImages[i]}, what would be i in this case?
Thank You
Ideally, your business objects and your UI should be completely separate, so your ItemsSource should not have Image UI objects
But that said, try and use an implicit style to set your properties
<telerik:RadCoverFlow.Resources>
<Style TargetType="{x:Type Image}">
<Setter Property="Height" Value="100" />
<Setter Property="Width" Value="100" />
<Setter Property="Stretch" Value="Uniform" />
<Setter Property="telerik:RadCoverFlow.EnableLoadNotification" Value="True" />
</Style>
</telerik:RadCoverFlow.Resources>

Categories