WPF combine icon and text in Listview with columns - wpf

I'm coding simple file explorer in WPF and I have Listview with 5 columns (Name, Extension, Size, Date, Attributes)
XAML looks this:
<ListView Name="ListView" BorderThickness="2,0,2,0" BorderBrush="Gray" Height="Auto" Width="Auto" >
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="450"/>
<GridViewColumn Header="Extension" DisplayMemberBinding="{Binding Extension}" Width="70"/>
<GridViewColumn Header="Size" DisplayMemberBinding="{Binding Size}" Width="80"/>
<GridViewColumn Header="Date" DisplayMemberBinding="{Binding Date}" Width="80"/>
<GridViewColumn Header="Attributes" DisplayMemberBinding="{Binding Attributes}" Width="60"/>
</GridView>
</ListView.View>
Then, I have class FileInfo with five properties, each binded to column via DisplayMemberBinding
public class FileInfo
{
public string Name { get; set; }
public string Extension { get; set; }
public string Size { get; set; }
public string Date { get; set; }
public string Attributes { get; set; }
}
var files = new List<FileInfo> { new FileInfo { Name = "Foo", Extension = ".sub", Date = "1.1.2015", Size = "3.05", Attributes = "H" } } //just as test
ListView.ItemsSource = files;
That works fine.
Now, in column Name I want to combine file name with its associated icon. And I don't know, how to do that. I don't want to create another column for icon, icon must be included in Name column.
Any ideas? Is there a way to do this programmatically, or do I need to modify XAML?

You need to create CellTemplate for your GridViewColumn like this
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="450">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="<Your Image Source>"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

Related

How can i bind data in ListViewItem?

I have a ListView with some Columns. One of Column contains two RadioButton.When i checked Radiobutton,i want change the binding value of the last column(it's header Name is Fee).I have no idea,can someone help me ?
<ListView x:Name="lvTimeView">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="ID" Width="175" DisplayMemberBinding="{Binding serverId}"></GridViewColumn>
<GridViewColumn Header="IP" Width="175" DisplayMemberBinding="{Binding serverIp}"></GridViewColumn>
<GridViewColumn x:Name="gvcTime" Header="Time" Width="400">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="30">
<RadioButton x:Name="rbOneMonth" Tag="1" Checked="rbChecked" Style="{StaticResource BoxRadioButton}" HorizontalAlignment="Left">OneMonth</RadioButton>
<RadioButton x:Name="rbTwoMonth" Tag="2" Margin="8,0,0,0" Checked="rbChecked" Style="{StaticResource BoxRadioButton}" HorizontalAlignment="Left">TwoMonth</RadioButton>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Fee" Width="100" DisplayMemberBinding="{Binding fee}">
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
First, forget about events in this example. This is a perfect example to leverage WPF binding...
Change your XAML to this.
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="ID" Width="175" DisplayMemberBinding="{Binding ServerId}"></GridViewColumn>
<GridViewColumn Header="IP" Width="175" DisplayMemberBinding="{Binding ServerIp}"></GridViewColumn>
<GridViewColumn Header="Time">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<RadioButton GroupName="{Binding ServerId}" IsChecked="{Binding OneMonth}">OneMonth</RadioButton>
<RadioButton GroupName="{Binding ServerId}" IsChecked="{Binding TwoMonth}" Margin="5,0,0,0">TwoMonth</RadioButton>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Fee" Width="100" DisplayMemberBinding="{Binding Fee}">
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
Pay attention to RadioButtons GroupName property. This is just so the radio buttons know they are a part of a radio button group so when you select one the other one unselects. We have to set this to something unique per row so I chose serverId. I hope this is unique in your case otherwise you will have to generate some Guid or something...
Next is the model...
public class Item : INotifyPropertyChanged
{
private string _serverId;
private string _serverIp;
private bool _oneMonth;
private bool _twoMonth;
private decimal _fee;
public event PropertyChangedEventHandler PropertyChanged;
public string ServerId
{
get => _serverId;
set
{
_serverId = value;
OnPropertyChanged(nameof(ServerId));
}
}
public string ServerIp
{
get => _serverIp;
set
{
_serverIp = value;
OnPropertyChanged(nameof(ServerIp));
}
}
public bool OneMonth
{
get => _oneMonth;
set
{
_oneMonth = value;
if(value)
Fee = 100;
OnPropertyChanged(nameof(OneMonth));
}
}
public bool TwoMonth
{
get => _twoMonth;
set
{
_twoMonth = value;
if(value)
Fee = 200;
OnPropertyChanged(nameof(TwoMonth));
}
}
public decimal Fee
{
get => _fee;
set
{
_fee = value;
OnPropertyChanged(nameof(Fee));
}
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Instantiate the model and add it to the data context...
public partial class MainWindow : Window
{
public IEnumerable<Item> Items => new Item[]
{
new Item { ServerId = "asia", ServerIp = "10.1.1.45" },
new Item { ServerId = "europe", ServerIp = "45.1.4.211" },
new Item { ServerId = "australia", ServerIp = "37.2.1.181" }
};
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}

Bind a custom class of controls to Listview/GridView as ListViewItem

I am facing some problem with binding the data to the controls in ListView/GridView as ListViweItem.
Requirement: Have to show a checkbox, Label, DropDown and a textbox per row which get data from all different sources.Here is the sample class:
class Data {
public CheckBox chk_box;
public Label lbl;
public ComboBox cmb_box;
public TextBox t_box;
public Data(String lbl_Data,List<String> cmb_box_Data) {
chk_box=new CheckBox();
lbl=new Label();
lbl.Content=lbl_Data;
cmb_box=new ComboBox();
cmb_box.ItemsSource=cmb_box_Data;
chk_box.Click += new RoutedEventHandler(chk_box_clicked);
...
}
private void chk_box_clicked(object Sender, RoutedEventArgs e){
if(chk_box.IsChecked == true) cmb_box.IsEnabled = false;
else cmb_box.IsEnabled = true;
}
}
Now i need to add this class' object as a ListViewItem, per control per column in ListView/GridView - dynamically, row by row and then after user makes selections access all the rows once again row by row and get values from these controls.
XAML code:
<ListView x:Name="TestGrid">
<ListView.View>
<GridView>
<GridViewColumn Header=" Select "/>
<GridViewColumn Header=" Label "/>
<GridViewColumn Header=" cmb_box "/>
<GridViewColumn Header=" t_box "/>
</GridView>
</ListView.View>
</ListView>
Since, the Items Source for all the controls is different, i cannot use ListView.ItemsSorce to bind data. Please suggest suitable options, or ways to accomplish the desired UI. I would like to make everything out from the controls given in VS only without using a third party dll(if possible).
Thank you for your time and suggestions in advance.
Check msdn.microsoft.com for binding
public class Datum
{
public bool Select { get; set; }
public string Name { get; set; }
public List<string> Items { get; set; }
}
<ListView ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Select">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Select, Mode=OneWay}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, Mode= OneWay}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=Items}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>

Change ListViewItem text color

I am currently creating ListViewItems programatically like so:
ListView.Items.Add(New With {Key .Name = ItemName, Key .DateCreated = ItemDateCreated, Key .Description = ItemDescription})
I have found no way of changing the color of the item, as I have not found a way of creating a ListViewItem with sub items in any other way than this one.
Is it possible to change the color of the item's text (or background if not possible), while still being able to have subitems?
EDIT - This is my XAML:
<ListView x:Name="ListView" Opacity="0.75">
<ListView.View>
<GridView x:Name="ListViewGridView">
<GridViewColumn Header="Name" Width="155" DisplayMemberBinding="{Binding Path=Name}"/>
<GridViewColumn Header="Date Created" Width="150" DisplayMemberBinding="{Binding Path=DateCreated}"/>
<GridViewColumn Header="Description" Width="250" DisplayMemberBinding="{Binding Path=Description}"/>
</GridView>
</ListView.View>
</ListView>
The following sample will set the first column's text to green. On a side note, you should probably wrap your "Name", "Date Created" and "Description" fields into an actual object and use it to create your ListViewItem with subitems instead of trying to create a new weakly typed object each time (I did this and attached the code if you are interested, obviously you can use any data type for members (not just string) but I was coding quickly).
Information on DataTemplates:
http://msdn.microsoft.com/en-us/library/system.windows.datatemplate(v=vs.110).aspx
XAML:
<ListView x:Name="ListView" Opacity="0.75">
<ListView.View>
<GridView x:Name="ListViewGridView">
<GridViewColumn Header="Name" Width="155">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" Foreground="{Binding Color}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Date Created" Width="150" DisplayMemberBinding="{Binding Path=DateCreated}"/>
<GridViewColumn Header="Description" Width="250" DisplayMemberBinding="{Binding Path=Description}"/>
</GridView>
</ListView.View>
</ListView>
C#:
// In method somewhere, won't work otherwise
ListView.Items.Add(new DataClass("Bob", "12/04/2013", "Person", Color.Green));
public class DataClass
{
public String Name { get; set; }
public String DateCreated { get; set; }
public String Description { get; set; }
public SolidBrushColor { get; set; }
public DataClass (string Name, String Date, String Desc, SolidBrushColor textColor)
{
this.Name = Name;
this.DateCreated = Date;
Description = Desc;
Color = textColor;
}
}

Binding textbox in ListView's header datatemplate to a filter property

I am creating a customized listview header that has the header text but also has a textbox that you can enter to filter the content of that column. My code currently looks like this:
<UserControl.Resources>
<DataTemplate x:Key="myHeaderTemplate">
<StackPanel>
<TextBlock FontSize="14" Foreground="DarkBlue" Margin="20,4" Text="{Binding}" />
<TextBox Text="" Margin="4,2" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
which is the definition for the header datatemplate containing the texbox; and the listview
<ListView ItemsSource="{Binding Path=MyData}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="Last Name" HeaderTemplate="{StaticResource myHeaderTemplate}"
DisplayMemberBinding="{Binding Path=Something}" />
<GridViewColumn Header="First Name" HeaderTemplate="{StaticResource myHeaderTemplate}"
DisplayMemberBinding="{Binding Path=Something}" />
<GridViewColumn Header="Address" HeaderTemplate="{StaticResource myHeaderTemplate}"
DisplayMemberBinding="{Binding Path=Tube}" />
</GridView>
</ListView.View>
</ListView>
I want to be able to build up a filter statement that I can apply to the listview rows, but to do that I have to get the data from each filter textbox in the header template.
Can I somehow bind the textboxes in the headers to properties on my viewmodel? If not is there some other way to get the text?
Thanks for any help.
You should be able to bind the header to a property like this:
<GridViewColumn
Header="{Binding LastNameFilter, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"
HeaderTemplate="{StaticResource myHeaderTemplate}"
DisplayMemberBinding="{Binding Path=Something}" />
The RelativeSource is needed to get to the DataContext of the ListView - you could also give it a name and use ElementName instead.
Now you can make a HeaderFilter class:
public class HeaderFilter
{
public string Name { get; set; }
public string Filter { get; set; }
}
Obviously you would need to extend that class to hook into the event when Filter is changed to perform the filtering.
Put a property for each column header on the object which is the DataContext for your ListView (same object which provides MyData probably)
public class SomeClass
{
....
public HeaderFilter LastNameFilter { get; set; }
....
}

WPF: Progress bar in ListView

I'm trying to display information from my ObservableCollection<MyData> in a ListView. MyData has:
string Name
string Location
int Progress
Using DataBinding, I'm able to display the Name and Location for all the items in my ObservableCollection<MyData> in their own column. But how can I add a Progress column with a ProgressBar inside? Progress is a percentage.
<ListView ItemsSource="{Binding PersonList}">
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="GameName" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Width="140" Header="Progress">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ProgressBar Maximum="100" Value="{Binding Progress}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Your ListView in XAML:
<ListView x:Name="DataView">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Path=Name}" />
<ProgressBar Height="20" Width="100" Value="{Binding Path=Progress}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code-behind:
internal class MyData
{
public string Name { get; set; }
public int Progress { get; set; }
}
...
var items = new ObservableCollection<MyData>();
items.Add(new MyData() { Name = "Some", Progress = 25 });
items.Add(new MyData() { Name = "Another", Progress = 91 });
DataView.ItemsSource = items;
Just bind Progress property in MyData to the ProgressBar.Value and set the expected MAX value as the ProgressBar.Maximum for example 50 below
<ProgressBar Maximum="50" Value="{Binding Progress}" ..

Resources