ListViewItem tooltip WPF - c#

What I need is that when mouse per listviewitem show me all data from each in a tooltip.
This is a part of my viewmdel
...
...
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
...
...
private ObservableCollection<Articulo> _articulos;
private Articulo _articuloSeleccionado;
public ObservableCollection<Articulo> Articulos
{
get { return _articulos; }
set
{
_articulos = value;
RaisePropertyChanged();
}
}
public Articulo ArticuloSeleccionado
{
get { return _articuloSeleccionado; }
set
{
_articuloSeleccionado = value;
RaisePropertyChanged();
}
}
My .xalm
<ListView Name="lvResultado"
ItemsSource="{Binding Articulos}"
SelectedItem="{Binding ArticuloSeleccionado}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Código de barras" Width="200" DisplayMemberBinding="{Binding CodigoDeBarras}"/>
<GridViewColumn Header="Descripción" Width="250" DisplayMemberBinding="{Binding Descripcion}"/>
</GridView>
</ListView.View>
</ListView>
Thank you for your help. I tried several things but no good result.

You can define an ItemContainerStyle that would set your tooltip template and content.
See an example below, here I define an UniformGrid to display multiple text lines in one column. You are free to setup your tooltip as you wish. You still need to tell the view which data properties need to be displayed in the tooltip.
<ListView ItemsSource="{Binding Articulos}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip">
<Setter.Value>
<UniformGrid Columns="1">
<TextBlock Text="{Binding CodigoDeBarras}"/>
<TextBlock Text="{Binding Descripcion}"/>
<TextBlock Text="{Binding AnyOtherProperty}"/>
</UniformGrid>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>

Related

Data binding from a complex ICollectionView in a WPF ItemContainerStyle

I have the following xaml:
<UserControl ... xmlns:dd="clr-namespace:AttachedBehaviours.DragDrop;assembly=AttachedBehaviours" ... >
<UserControl.Resources>
<dd:BindingProxy x:Key="library_proxy"
Binding="{Binding SelectedItems.Count, ElementName=library}" />
</UserControl.Resources>
<ListView x:Name="library" ItemsSource="{Binding View}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Value}" />
</GridView.Columns>
</GridView>
</ListView.View>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="dd:DragDropMulti.DragDropPreviewControl">
<Setter.Value>
<dd:DragDropPreviewBase>
<dd:DragDropPreviewBase.Template>
<ControlTemplate TargetType="dd:DragDropPreviewBase">
<TextBlock x:Name="tblk__preview"
Text="{Binding Binding, Source={StaticResource library_proxy}}" />
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Binding, Source={StaticResource library_proxy}}"
Value="1">
<DataTrigger.Setters>
<Setter TargetName="tblk__preview"
Property="Text"
Value="{Binding Name}" />
</DataTrigger.Setters>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</dd:DragDropPreviewBase.Template>
</dd:DragDropPreviewBase>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</UserControl>
The problem I'm having is that if I generate my ICollectionView (the "View" in ItemsSource="{Binding View}") with a basic CollectionViewSource, everything works as expected. E.g.:
View = new CollectionViewSource { Source = Models }.View;
However, if I use something more complex, the Setter binding of the DataTrigger doesn't work. E.g.:
View =
new CollectionViewSource
{
Source =
Models
.Join(
Lookups
, model => model.ID
, lookup => lookup.Key
, (model, lookup) =>
new ComplexModel
{
ID = model.ID,
Name = model.Name,
Value = lookup.Value
}
)
}
.View;
I get the error:
System.Windows.Data Error: 40 : BindingExpression path error: 'Name' property not found on 'object' ''MainWindowViewModel' (HashCode=17911681)'.
MainWindowViewModel is the overall DataContext (outside of the UserControl), so it's as though the DataContext has not been set.
Why would this be the case?

Checkbox ListView WPF C#

I will start developing for WPF and I have a doubt.
I created a ListView with the Binding property to the next ExtComandaDTO the object. The property in "seleciona" has relationship with a checkbox, but I have following problem.
When I click the checkbox it calls the normal event, but when I change the value of "seleciona" at runtime checkbox in my listview is selected but does not call the event check.
There is missing from Listview to be called the event some attribute?
<ListView x:Name="LvwComanda" Grid.Column="0"
Background="{x:Null}"
Margin="40,36,40,40"
SelectedItem="{Binding SelectedExtComanda}"
ItemsSource="{Binding ObsExtComanda, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.RowSpan="2" >
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Finaliza Comanda" Checked="LvwComandaRowFinalizaComanda_Click" Unchecked="LvwComandaRowFinalizaComanda_Click"></MenuItem>
</ContextMenu>
</ListView.ContextMenu>
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding finaliza_pendente}" Value="true">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding finalizada}" Value="true">
<Setter Property="Foreground" Value="DarkViolet" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.View>
<GridView >
<GridViewColumn Width="30">
<GridViewColumn.CellTemplate>
<DataTemplate >
<CheckBox Name="ChkComanda" IsChecked="{Binding seleciona.IsChecked, Mode=TwoWay}" Checked="Checked_LvwComandaRow" Unchecked="Unchecked_LvwComandaRow" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="Auto" Header="Comanda" DisplayMemberBinding="{Binding nr_comanda}"/>
<GridViewColumn Width="Auto" Header="Taxa Servico" DisplayMemberBinding="{Binding taxa_servico}" />
<GridViewColumn Width="Auto" Header="Finalizada" DisplayMemberBinding="{Binding finalizada, Converter={StaticResource ReplaceConvertSimNao}}" />
<GridViewColumn Width="Auto" Header="Observacao" DisplayMemberBinding="{Binding observacao}"/>
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" BorderBrush="#FFA4B97F" BorderThickness="0,0,0,1">
<Expander.Header>
<DockPanel>
<DockPanel.ContextMenu>
<ContextMenu Loaded="LvwComandaHeaderContextMenu_Loaded">
<MenuItem Header="Libera Mesa" Checked="LvwComandaHeaderLiberaMesa_Click" Unchecked="LvwComandaHeaderLiberaMesa_Click" />
</ContextMenu>
</DockPanel.ContextMenu>
<CheckBox x:Name="HeaderCheckBox" Checked="Checked_LvwComandaHeader" Unchecked="Unchecked_LvwComandaHeader">
<StackPanel Orientation="Horizontal">
<TextBlock FontWeight="Bold" Text="{Binding Name, Converter={StaticResource ReplaceConvertMesaId}}" Margin="5,0,0,0"/>
<TextBlock Width="Auto" Text=" " />
<TextBlock FontWeight="Bold" Width="Auto" Text="{Binding Name, Converter={StaticResource ReplaceConvertMesaGrupo}}" />
<TextBlock Text=" ("/>
<TextBlock Text="{Binding ItemCount, Converter={StaticResource ReplaceConvertComanda}}"/>
<TextBlock Text=")"/>
</StackPanel>
</CheckBox>
</DockPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
#region Event List Row Comanda
private void Checked_LvwComandaRow(object sender, RoutedEventArgs e)
{
this.Handle_LvwComandaRow((CheckBox)sender, true);
}
private void Unchecked_LvwComandaRow(object sender, RoutedEventArgs e)
{
this.Handle_LvwComandaRow((CheckBox)sender, false);
}
private void Handle_LvwComandaRow(CheckBox sender, bool check)
{
if (sender.DataContext is ExtComandaDTO)
{
var row = (ExtComandaDTO)sender.DataContext;
if (check)
{
ObsExtComanda.FindAll(c => c.seleciona && c.id_mesa != row.id_mesa).ForEach(c => c.seleciona = false);
}
bool bolComandaSelected = ObsExtComanda.Exists(c => c.seleciona);
BtPagamento.IsEnabled = bolComandaSelected;
BtImprimir.IsEnabled = bolComandaSelected;
this.PrepareObsPedido(check, row);
this.PrepareObsComandaPagto(check, row);
}
}
public class ExtComandaDTO : ComandaDTO, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
private Boolean _seleciona;
private Boolean _finaliza_pendente;
public Boolean seleciona
{
get { return _seleciona; }
set { _seleciona = value; OnPropertyChanged("seleciona"); }
}
public new Boolean finaliza_pendente
{
get { return _finaliza_pendente; }
set { _finaliza_pendente = value; OnPropertyChanged("finaliza_pendente"); }
}
}
Checked and Unchecked are events fired by the UI (not a set).
Handle that stuff in the set if you want to catch changes from code.

How to verify a string changed from a textbox in listview is not the same as any exiting ones

I have a ListView box containing TextBoxes that allow users to add and change the content. How do I verify that the content that is changed is not the same as any exiting one in C# behind?
Xaml:
<ListView
x:Name="_regionQueryListBox"
Width="122"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
DataContext="{Binding}"
IsSynchronizedWithCurrentItem="True"
Style="{StaticResource ListViewRegionSelectorStyle}"
ItemsSource="{Binding Path=Model}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectionChanged="_regionQueryListBox_SelectionChanged">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Region" Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
MaxLength="16"
Width="110"
Margin="-2,0,0,0"
Padding="-2,0,0,0"
Text="{Binding Path=RegionName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Yes, it is MVVM. I have a validation for adding same item and you can find the Model like below:
private void OnQueryCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
if (Model.Count == 0)
{
CurrentRegionViewModel = null;
}
if (args.Action == NotifyCollectionChangedAction.Add)
{
RegionQuery addedRegionQuery = args.NewItems.OfType<RegionQuery>().FirstOrDefault();
if (addedRegionQuery != null)
{
string name = addedRegionQuery.RegionName;
while (Model.Any(q => q.RegionName == name && q != addedRegionQuery))
{
name += "*";
}
addedRegionQuery.RegionName = name;
}
}

How to add a tooltip for a datagrid header, where the header text is generated dynamically?

I need to add a tooltip for a column header of a DataGrid (Silverlight 4). I will generate the number of columns and column header text dynamically.
GridColumnCreation(....)
{
IEnumerable allHeaderText = /* Linq query */;
}
How to use this collection to set a tooltip?
This can be done even more simply than in #Farukh's answer:
<data:DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="ToolTipService.ToolTipProperty"
Value="Your tool tip here" />
</Style>
</data:DataGridTextColumn.HeaderStyle>
Or, if you need to do it in code:
var style = new Style(typeof(DataGridColumnHeader));
style.Setters.Add(new Setter(ToolTipService.ToolTipProperty,
"Your tool tip here"));
column.HeaderStyle = style;
In case it might help anyone. It works when using TooTip property.
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="ToolTip" Value="{Binding}"/>
</Style>
</DataGridTextColumn.HeaderStyle>
If you do not want to create a new style for the Header, simply add a TextBlock for your column header and set the tooltip on it.
<DataGridTextColumn>
<DataGridTextColumn.Header>
<TextBlock Text="ColumnA" ToolTip="ColumnA Tooltip"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
This can be done by using DataGridTextColumn & DataGridTextColumn.HeaderStyle. In the headerstyle tag, use the ToolTipService and bind the content to the dynamic values generated. Here's a sample code for this...
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="First Name" Binding="{Binding FName}" >
<data:DataGridTextColumn.HeaderStyle>
<Style TargetType="dataprimitives:DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ContentControl Content="{Binding}">
<ToolTipService.ToolTip>
<ToolTip Content="Tooltip First" />
</ToolTipService.ToolTip>
</ContentControl>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</data:DataGridTextColumn.HeaderStyle>
</data:DataGridTextColumn>
<data:DataGridTextColumn Header="Last Name" Binding="{Binding LName}">
<data:DataGridTextColumn.HeaderStyle>
<Style TargetType="dataprimitives:DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ContentControl Content="{Binding}">
<ToolTipService.ToolTip>
<ToolTip Content="Tooltip Second"></ToolTip>
</ToolTipService.ToolTip>
</ContentControl>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</data:DataGridTextColumn.HeaderStyle>
</data:DataGridTextColumn>
<data:DataGridTextColumn Header="City" Binding="{Binding City}">
<data:DataGridTextColumn.HeaderStyle>
<Style TargetType="dataprimitives:DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ContentControl Content="{Binding}">
<ToolTipService.ToolTip>
<ToolTip Content="Tooltip Third"></ToolTip>
</ToolTipService.ToolTip>
</ContentControl>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</data:DataGridTextColumn.HeaderStyle>
</data:DataGridTextColumn>
</data:DataGrid.Columns>
</data:DataGrid>
</Grid>
where Custdetails.. is something like this..
class Customer
{
public string LName { set; get; }
public string FName { set; get; }
public string City { set; get; }
}
DataBinding...
List<Customer> customers = new List<Customer>
{
new Customer { LName="Alan", FName="Ameen", City="New York" },
new Customer { LName="Forgeard", FName="Steven", City="Mumbai" },
new Customer { LName="Angur", FName="Paul", City="São Paulo" }
};
dgCustDetails.ItemsSource = customers;
This would display the header tooltips... To make it dynamic.. Replace the ToolTip Content with Binding & the desired value...

WPF ListView: Aligning text in selected columns

<ListView ItemsSource="{Binding MyData}">
<ListView.View>
<GridView>
<GridViewColumn Header="col1" DisplayMemberBinding="{Binding Path=value1}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock TextAlignment="Right" Text="{Binding Path=value1}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="col2">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock TextAlignment="Center" Text="{Binding Path=value2}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="col3" DisplayMemberBinding="{Binding Path=value3}"/>
</GridView>
</ListView.View>
<ListView ItemsSource="{Binding MyData}">
col1 is supposed to be right-aligned. (Not working)
col2 is supposed to be center-aligned. (Working)
col3 is supposed to be left-aligned. (Working)
Is there a reason DisplayMemberBinding is overriding CellTemplate? If so, is there a fix for this (while still using DisplayMemberBinding)?
Edit: I ended up implementing it like this:
<Window xmlns:util="clr-namespace:TestProject.Util">
<Window.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
<Style TargetType="GridViewColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
</Style>
<DataTemplate x:Key="value1Template">
<TextBlock TextAlignment="Right" Text="{Binding Path=value1}"/>
</DataTemplate>
<DataTemplate x:Key="value2Template">
<TextBlock TextAlignment="Right" Text="{Binding Path=value2}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding MyData}" IsSynchronizedWithCurrentItem="True" util:GridViewSort.Command="{Binding SortCommand}">
<ListView.View>
<GridView>
<GridViewColumn Header="col1" CellTemplate="{StaticResource value1Template}" util:GridViewSort.PropertyName="value1"/>
<GridViewColumn Header="col2" CellTemplate="{StaticResource value2Template}" util:GridViewSort.PropertyName="value2"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
In the code behind:
private RelayCommand sortCommand;
public ICommand SortCommand { get { return sortCommand ?? (sortCommand = new RelayCommand(Sort)); } }
private void Sort(object param)
{
var propertyName = param as string;
var view = CollectionViewSource.GetDefaultView(MyData);
var direction = ListSortDirection.Ascending;
if (view.SortDescriptions.Count > 0)
{
var currentSort = view.SortDescriptions[0];
if (currentSort.PropertyName == propertyName)
direction = currentSort.Direction == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
view.SortDescriptions.Clear();
}
if (!string.IsNullOrEmpty(propertyName))
view.SortDescriptions.Add(new SortDescription(propertyName, direction));
}
DisplayMemberBinding has the highest priority. You can not use it combined with CellTemplate. See here in the remarks section.
If you want to right-or center-align the content, you must declare the CellTemplate with the binding (as you did) and remove the DisplayMemberBinding-attribute. If you also want to change the column header alignment, you must also set the GridViewColumn.Header-property.
Just add the following after your Window tag:
<Window.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Right" />
</Style>
</Window.Resources>

Categories