different Popups for different columns of a DataGrid
-
20. srpna 2012 7:18
I have a Visual C# 2010 Express DataGrid that is populated with a
datatable which itself refreshes with 1000s records every few
minutes.Depending on which column the user puts the mouse on, I
want to show a UserControl Popup relevant to that column. The Popup
UserControl serves to further navigate the properties of that column
field. For now the UserControl is a simple form that shows the datagrid
column/value the mouse is over
Please find the source code below.For column JOB_NAME I want to show Popup UserControlJobName, for column JOB_DATE I want to show Popup UserControlJobDate.
For other columns, no popup.
The popup should stay while the mouse is either on the DataGrid column field or on the popup and disappear otherwiseMainWindow.xaml
<Window x:Class="DataGridBinding.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"></ColumnDefinition> </Grid.ColumnDefinitions> <Button Name="btnStart" Grid.Row="0" MaxWidth="100" Click="btnStart_Click">Start</Button> <DataGrid Name="dgJobs" Grid.Row="1" ItemsSource="{Binding}" IsReadOnly="True"> <DataGrid.RowStyle> <Style TargetType="{x:Type DataGridRow}"> <Style.Triggers> <DataTrigger Binding="{Binding JOB_STATUS}" Value="RUNNING"> <Setter Property="Foreground" Value="Blue"/> </DataTrigger> <DataTrigger Binding="{Binding JOB_STATUS}" Value="FAILURE"> <Setter Property="Foreground" Value="Red"/> </DataTrigger> <DataTrigger Binding="{Binding JOB_STATUS}" Value="SUCCESS"> <Setter Property="Foreground" Value="Green"/> </DataTrigger> <DataTrigger Binding="{Binding JOB_STATUS}" Value="ON_HOLD"> <Setter Property="Background" Value="Gray"/> </DataTrigger> </Style.Triggers> </Style> </DataGrid.RowStyle> </DataGrid> </Grid> </Window>
MainWindow.xaml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Data; namespace DataGridBinding { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { DataTable dt = new DataTable(); public MainWindow() { InitializeComponent(); dt.Columns.Add("JOB_NAME", typeof(string)); dt.Columns.Add("JOB_TYPE", typeof(string)); dt.Columns.Add("JOB_STATUS", typeof(string)); dt.Columns.Add("JOB_DATE", typeof(DateTime)); } private void btnStart_Click(object sender, RoutedEventArgs e) { dt.Clear(); dt.Rows.Add("JOB1", "TYPEA", "INACTIVE", System.DateTime.Now); dt.Rows.Add("JOB2", "TYPEB", "SUCCESS", System.DateTime.Now); dt.Rows.Add("JOB3", "TYPEA", "FAILURE", System.DateTime.Now); dt.Rows.Add("JOB4", "TYPEC", "RUNNING", System.DateTime.Now); dt.Rows.Add("JOB5", "TYPEC", "ON_HOLD", System.DateTime.Now); dgJobs.DataContext = dt; } } }
UserControlJobName.xaml
<UserControl x:Class="DataGridBinding.UserControlJobName" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition Width="Auto"></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0">Column Name under mouse:</TextBlock> <TextBlock Grid.Row="0" Grid.Column="1" Name="TextBlockColName" Foreground="Blue">col name here</TextBlock> <TextBlock Grid.Row="1">Column Value under mouse:</TextBlock> <TextBlock Grid.Row="1" Grid.Column="1" Name="TextBlockColValue" Foreground="Blue">col value here</TextBlock> </Grid> </UserControl>
UserControlJobDate.xaml
<UserControl x:Class="DataGridBinding.UserControlJobDate" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition Width="Auto"></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0">Column Name under mouse:</TextBlock> <TextBlock Grid.Row="0" Grid.Column="1" Name="TextBlockColName" Foreground="Blue">col name here</TextBlock> <TextBlock Grid.Row="1">Column Value under mouse:</TextBlock> <TextBlock Grid.Row="1" Grid.Column="1" Name="TextBlockColValue" Foreground="Blue">col value here</TextBlock> <Calendar Grid.Row="2" Name="CalendarJobs"></Calendar> </Grid> </UserControl>
I need help in implementing popup for the datagrid column.
Highly appreciate a working solution !
Thanks,
-sri
sri
Všechny reakce
-
20. srpna 2012 8:10
This is WPF, so you can style anything.
Perhaps counter-intuitively this includes tooltips and you can assign a different style per column. Specifically Cellstyle.
So you need some style for each tooltip but here's how you set a very simple style on a column tooltip.
<DataGridTextColumn.ElementStyle> <Style TargetType="{x:Type TextBlock}"> <Setter Property="ToolTip" Value="{Binding Description}" /> <Setter Property="TextWrapping" Value="Wrap" /> </Style> </DataGridTextColumn.ElementStyle> -
20. srpna 2012 8:55
Thanks Andy,
can you please demo with my code for 2 datagrid columns and the tooltip to call the usercontrol? I earlier (last week) spent a lot of time with datagrid text columns but couldn't get the desired result. a working solution would be very learning for me
Thanks
sri
-
20. srpna 2012 12:00Moderátor
Hi ysrini
Andy is correct. However, if it were me, I would use a higher level than the generated item, like the TextBlock of a DataGridTextColumn. I'd target the DataGridCell. Give this a go:
<Window x:Class="WpfApplication64.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <TextBlock x:Key="Tooltip1" Text="{Binding StringFormat='TT1={0}'}"/> <TextBlock x:Key="Tooltip2" Text="{Binding StringFormat='TT2={0}'}"/> </Window.Resources> <Grid Name="displayGrid"> <DataGrid ItemsSource="{Binding MyCollection}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding}" Header="Col 1"> <DataGridTextColumn.CellStyle> <Style TargetType="DataGridCell"> <Setter Property="ToolTip" Value="{StaticResource Tooltip1}"/> </Style> </DataGridTextColumn.CellStyle> </DataGridTextColumn> <DataGridComboBoxColumn ItemsSource="{Binding}" Header="Col 2" > <DataGridComboBoxColumn.CellStyle> <Style TargetType="DataGridCell"> <Setter Property="ToolTip" Value="{StaticResource Tooltip2}"/> </Style> </DataGridComboBoxColumn.CellStyle> </DataGridComboBoxColumn> </DataGrid.Columns> </DataGrid> </Grid> </Window>using System.ComponentModel; using System.Windows; using System.Collections.Generic; namespace WpfApplication64 { public partial class MainWindow : Window { public List<string> MyCollection { get; set; } public MainWindow() { InitializeComponent(); MyCollection = new List<string> { "one", "two" }; DataContext = this; } } }In this example, I am using TextBlocks as the tooltips, instead of actual UserControls, but it's the same thing of course.
Regards,
Pete
#PEJL
- Upravený XAML guyMicrosoft Community Contributor, Moderator 20. srpna 2012 12:06
- Navržen jako odpověď XAML guyMicrosoft Community Contributor, Moderator 24. srpna 2012 20:30
- Označen jako odpověď ysrini 24. srpna 2012 22:55
-
20. srpna 2012 23:54
Hi XAML guy, your example works, however when I use datatable instead it doesn't.
code behind:
btnStart is a button that will populate the datatable. In real time a timer and some functions will run queries and update the datatable periodically, that's why I didn't put this code in the InitializeComponent.
MainWindow.xamls.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Data; namespace DataGridBinding { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { DataTable dt = new DataTable(); public MainWindow() { InitializeComponent(); dt.Columns.Add("JOB_NAME", typeof(string)); dt.Columns.Add("JOB_TYPE", typeof(string)); dt.Columns.Add("JOB_STATUS", typeof(string)); dt.Columns.Add("JOB_DATE", typeof(DateTime)); } private void btnStart_Click(object sender, RoutedEventArgs e) { dt.Clear(); dt.Rows.Add("JOB1", "TYPEA", "INACTIVE", System.DateTime.Now); dt.Rows.Add("JOB2", "TYPEB", "SUCCESS", System.DateTime.Now); dt.Rows.Add("JOB3", "TYPEA", "FAILURE", System.DateTime.Now); dt.Rows.Add("JOB4", "TYPEC", "RUNNING", System.DateTime.Now); dt.Rows.Add("JOB5", "TYPEC", "ON_HOLD", System.DateTime.Now); dgJobs.DataContext = dt; } } }The DataGrid dgJobs DataContext is set to dt in the code behind in the btnStart_Click as show above
In the designer code, the Datagrid simply has the line
ItemsSource="{Binding}"MainWindow.xaml
<Window x:Class="DataGridBinding.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <TextBlock x:Key="Tooltip1" Text="{Binding StringFormat='TT1={0}'}"/> <TextBlock x:Key="Tooltip2" Text="{Binding StringFormat='TT2={0}'}"/> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"></ColumnDefinition> </Grid.ColumnDefinitions> <Button Name="btnStart" Grid.Row="0" MaxWidth="100" Click="btnStart_Click">Start</Button> <DataGrid Name="dgJobs" Grid.Row="1" ItemsSource="{Binding}" IsReadOnly="True"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding}" Header="JOB_NAME"> <DataGridTextColumn.CellStyle> <Style TargetType="DataGridCell"> <Setter Property="ToolTip" Value="{StaticResource Tooltip1}"/> </Style> </DataGridTextColumn.CellStyle> </DataGridTextColumn> <DataGridComboBoxColumn ItemsSource="{Binding}" Header="JOB_DATE" > <DataGridComboBoxColumn.CellStyle> <Style TargetType="DataGridCell"> <Setter Property="ToolTip" Value="{StaticResource Tooltip2}"/> </Style> </DataGridComboBoxColumn.CellStyle> </DataGridComboBoxColumn> </DataGrid.Columns> </DataGrid> </Grid> </Window>I see the JOB_NAME, JOB_DATE columns twice in the datagrid, one from the datatable and the other from DataGridTextColumn
Why couldn't the datagrid map the DataGridTextColumn name with column name in the datatable?
Can you please use this code and help where to fix?
Thanks,
-sri
sri
-
21. srpna 2012 0:58Moderátor
Replace the TextBlock in my example entirely with your own UserControls:
<Window.Resources> <local:MyUserControl1 x:Key="Tooltip1"
MyProperty="{Binding}"/> <local:MyUserControl2 x:Key="Tooltip2"
MyProperty="{Binding}"/> </Window.Resources>I was just using a TextBlock in my example as a "bindable control", so I could show passing the properties through to the control. You said you wanted your tooltips to show different "UserControls", so I used a TextBlock instead of whatever your UserControls are.
The DataRowView is of course exactly the data you wanted, and could be passed into your UserControls. In my example, I only use a "List of string", so I pass the binding straight through to the Text property of the TextBox. I'd suspect you'd pass the DataRowView through to the UserControl to consume.
So in my example, it is showing a TextBlock instead of your UserControl you mention, and in your followup, you still show my TextBlock, correctly showing the ToString representation of the bound data object.
I hope that is clearer for you now.
Regards,
Pete
#PEJL
- Upravený XAML guyMicrosoft Community Contributor, Moderator 21. srpna 2012 0:59 typos
- Navržen jako odpověď XAML guyMicrosoft Community Contributor, Moderator 24. srpna 2012 20:29
-
24. srpna 2012 20:23
Thanks Pete, for now i am using just a regular TextBlock tooltip and used your example. Except that when I use datatable as source instead of List collection, I get duplicate columns in the DataGrid and only one the the duplicates get the tooltip.
How to tell DataGrid to map a named DataGridTextColumn to bind with the column name in the datatable and not create a new one?
Thanks,
-sri
sri
-
24. srpna 2012 20:28Moderátor
Do you have AutogenerateColumns=False?
Please mark off all the replies above that helped AND/OR answered your questions, and start a new thread - with some sample xaml and code. This ensures your thread title is targetted for fellow searchers.
I'm very glad my previous suggestion solved your initial issue.
Best regards,
Pete#PEJL
- Navržen jako odpověď XAML guyMicrosoft Community Contributor, Moderator 24. srpna 2012 20:30