different Popups for different columns of a DataGrid

Odpovědět different Popups for different columns of a DataGrid

  • 20. srpna 2012 7:18
     
      Obsahuje kód

    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 otherwise

    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">
        <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
     
      Obsahuje kód

    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:00
    Moderátor
     
     Odpovědět Obsahuje kód

    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


  • 20. srpna 2012 23:54
     
      Obsahuje kód

    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

    data grid columns tootlip

    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:58
    Moderátor
     
     Navržená odpověď Obsahuje kód

    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


  • 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:28
    Moderátor
     
     Navržená odpověď

    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