I have a listview with 5 columns. In the first column i insert an image in wich i have an event MouseClicked event. What i want to accomplish is when i click the image from row 5 , to get the name of item in row 5 - column 2;
This is my code so far :
<ListView x:Name="HistoryListB">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="#FF515050"/>
<Style.Triggers>
<Trigger Property="Control.IsMouseOver" Value="true">
<Setter Property="Background" Value="#FF515050"/>
<Setter Property="BorderBrush" Value="#FF3B3A3A"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
<GridViewColumn Width="90" Header="Image" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Name="Favorite" Width="12" Height="12" Source="{Binding ImageSource}" MouseLeftButtonDown="Image_MouseLeftButtonDown" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="90" Header="Time Added" DisplayMemberBinding="{Binding Time}" />
<GridViewColumn Width="110" Header="Status" DisplayMemberBinding="{Binding Status}"/>
<GridViewColumn Width="290" Header="ItemTitle" DisplayMemberBinding="{Binding ItemTitle}"/>
<GridViewColumn Width="50" Header="Duration" DisplayMemberBinding="{Binding Duration}"/>
</GridView>
</ListView.View>
</ListView>
And i add items in listview like this. I have a class and a list like this :
public class HistoryItems
{
public string Time { get; set; }
public string Status { get; set; }
public string ItemTitle { get; set; }
public string Duration { get; set; }
public ImageSource ImageSource { get; set; }
}
IList<HistoryItems> SHistoryItems { get; set; }
And then add the items :
SHistoryItems = new List<HistoryItems>() {
new HistoryItems () {
Time = DateTime.Now.ToString("HH:mm:ss tt"),
Status = "Started Playing : ",
ItemTitle = StationL.StationName
}
};
foreach (var item in SHistoryItems)
HistoryListB.Items.Add(SHistoryItems);
And in my code i want to get the name of the item from same row but 2nd column :
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
TextBlock1.Text = ?? THE NAME OF THE SECOND COLUMN IN THE SAME ROW ?? ;
}
You can use the Tag property of the Image to hold the HistoryItem then you can access through the sender argument in the event handler.
Example:
Xaml:
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Name="Favorite" Width="12" Height="12" Source="{Binding ImageSource}" Tag="{Binding}" MouseLeftButtonDown="Image_MouseLeftButtonDown" />
</DataTemplate>
</GridViewColumn.CellTemplate>
Code:
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var image = sender as Image;
if (image != null && image.Tag is HistoryItems)
{
TextBlock1.Text = (image.Tag as HistoryItems).ItemTitle;
}
}
Related
this is XAMl code
Image Icon and string don't appear in ListView in WPF
What's wrong?
Not only the image, but also other text strings do not appear. Trying other methods says that the ItemSource is overlap.
Is the binding not being applied?
<GroupBox Grid.Column="1" Grid.RowSpan="2" Background="Aqua">
<StackPanel Orientation="Vertical" Background="Aquamarine" Margin="5">
<StackPanel.Resources>
<Style x:Key="ListviewStyle" TargetType="{x:Type ListView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListView}">
<Border x:Name="corner"
CornerRadius="9"
Background="White"
Height="1000">
<ContentPresenter
VerticalAlignment="Center"
HorizontalAlignment="Center"
/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<TextBlock Text="I/O Input"
FontSize="30"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="10"/>
<ListView Style="{StaticResource ListviewStyle}"
x:Name="lv_input">
<ListView.View>
<GridView>
<GridViewColumn Width="50" Header="InputStatus">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding InputStatus}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="200" Header="InputName"
DisplayMemberBinding="{Binding InputName}"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</GroupBox>
this is behind code
Image Icon and string don't appear in ListView in WPF
What's wrong?
Not only the image, but also other text strings do not appear. Trying other methods says that the ItemSource is overlap.
Is the binding not being applied?
enter code here
public partial class IOSetPage : Page
{
public ObservableCollection<ListViewItemsData> ListViewItemsCollections { get { return ListViewItemsCollections; } }
ObservableCollection<ListViewItemsData> _ListViewItemsCollections = new ObservableCollection<ListViewItemsData>();
public IOSetPage()
{
InitializeComponent();
ListViewItemsCollections.Add(new ListViewItemsData()
{
InputStatus = "/Image/inputdisconnect.png",
InputName = "ASFWQEFAasdfqerwefc"
});
lv_input.ItemsSource = ListViewItemsCollections;
}
public class ListViewItemsData
{
public string InputStatus { get; set; }
public string InputName { get; set; }
}
}
Considering the example you've provided, it appears you have a typo on the 3rd line of your C# code. The property getter should be returning _ListViewItemsCollections like this:
public ObservableCollection<ListViewItemsData> ListViewItemsCollections { get { return _ListViewItemsCollections; } }
Also, I noticed that you are using ItemsSource directly, rather than setting the DataContext on the lv_input ListView. Whilst ItemsSource may work after fixing the typo, you may encounter unexpected behavior when trying to use item templates etc...
A more correct (but not perfect) way of doing what you are attempting would look like this:
public partial class IOSetPage : Page
{
IOSetPageView view;
public IOSetPage()
{
InitializeComponent();
view = new IOSetPageView();
view.Items.Add(new ListViewItemsData()
{
InputStatus = "/Image/inputdisconnect.png",
InputName = "ASFWQEFAasdfqerwefc"
});
lv_input.DataContext = view;
}
}
public class IOSetPageView
{
public ObservableCollection<ListViewItemsData> Items { get; }
= new ObservableCollection<ListViewItemsData>();
}
public class ListViewItemsData
{
public string InputStatus { get; set; }
public string InputName { get; set; }
}
With the XAML for the ListView looking like this:
<ListView Style="{StaticResource ListviewStyle}" ItemsSource="{Binding Items}" x:Name="lv_input">
<ListView.View>
<GridView>
<GridViewColumn Width="50" Header="InputStatus">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding InputStatus}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="200" Header="InputName"
DisplayMemberBinding="{Binding InputName}"/>
</GridView>
</ListView.View>
</ListView>
Notice how the ItemSource is now bound to the Items property of the view class I created. To improve further, you could implement the INotifyPropertyChanged interface for your ListViewItemsData class which would allow the ListView to update in real time when you modify a property.
I've been trying to replicate the Listview like the screenshot below
enter image description here
But my problem is I can't make it work. I'm pretty new to MVVM
This is my xaml code
<ListView Margin="10,10,10,6" x:Name="BusinessListView">
<ListView.View>
<GridView>
<GridViewColumn Header="Company" DisplayMemberBinding="{Binding Company}" />
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" Text="{Binding BusinessType}"></TextBlock>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
And below is my viewmodel code
List<BusinessM> businesses = new List<BusinessM>();
businesses.Add(new BusinessM
{
BusinessType = "Enterprise",
ListBusiness = new List<BusinessInfo>
{
new BusinessInfo {Company = "Microsoft"}
}
});
BusinessListView.ItemsSource = businesses;
Model
public class BusinessM
{
public string BusinessType { get; set; }
public List<BusinessInfo> ListBusiness { get; set; }
public BusinessM()
{
ListBusiness = new List<BusinessInfo>();
}
}
public class BusinessInfo
{
public string Company { get; set; }
}
When I run the program it returns an error:
System.Windows.Data Error: 40 : BindingExpression path error: 'Company' property not found
What's wrong with my code? What I understand is I'm not referencing properly the property Company into the Listview?
If it's that's the case. How can I do it properly. I've been trying to solve it myself but I can't make it work.
Thank you.
You are getting the error specified because of the way your data structure is bounded to listview's item source property. Typically, you would have a flattened list of model and then you would use ColllectionViewSource to apply Grouping and/or Sorting on the collection.
In posted code, you are binding ItemSource to list of BusinessM which means each list view item represents object of type BusinessM. So when you bind GridViewColumn to Company,it expects BusinessM type to have a property with similar name, which by the way, is not the case.
I have modified you code so that I can explain you how it should be done (IMO) with example.
Model:
public class BusinessM
{
public string BusinessType { get; set; }
public string Company { get; set; }
}
Code behind (xaml.cs):
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
CollectionViewSource cvs = new CollectionViewSource();
cvs.Source = GenerateData();
cvs.GroupDescriptions.Add(new PropertyGroupDescription(nameof(BusinessM.BusinessType)));
BusinessListView.ItemsSource = cvs.View;
}
private List<BusinessM> GenerateData()
{
List<BusinessM> businesses = new List<BusinessM>();
for (int i = 1; i <= 10; i++)
{
for (int j = 1; j <= 5; j++)
{
businesses.Add(new BusinessM
{
BusinessType = $"Type {i}",
Company = $"{i}{j}"
});
}
};
return businesses;
}
}
View (xaml):
<ListView Margin="10,10,10,6" x:Name="BusinessListView">
<ListView.View>
<GridView>
<GridViewColumn Header="" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Company" DisplayMemberBinding="{Binding Company}" />
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="True" Header="{Binding Name}">
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
I am new to WPF, I have the following xaml code for list view:
<ListView x:Name="listView1" ItemsSource="{Binding Processes1}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="470" Margin="10,95,150,6" Width="565" SelectionChanged="NetscalerCfgView_listView1_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="Line" DisplayMemberBinding="{Binding srcCfgLineNum}"/>
<GridViewColumn Header="Source Config" DisplayMemberBinding="{Binding srcConfigText}"/>
</GridView>
</ListView.View>
</ListView>
I have the class SrcListViewInfo which I am displaying in listview:
public class SrcListViewInfo
{
public int srcCfgLineNum { get; set; }
public string srcConfigText { get; set; }
}
I have declared it in windows load event like this:
public ObservableCollection<SrcListViewInfo> processes1 = null;
processes1 = new ObservableCollection<SrcListViewInfo>();
I want to color the row background dynamically in a different function under different cases dynamically, for example:
case DiffResultSpanStatus.DeleteSource:
for (i = 0; i < drs.Length; i++)
{
SrcListViewInfo newInfo = new SrcListViewInfo();
newInfo.BackgroundColor = new SolidColorBrush(Colors.Red);
// newInfo.BackgroundColor = Brushes.Red;
newInfo.srcCfgLineNum = cnt;
newInfo.srcConfigText = ((TextLine)source.GetByIndex(drs.SourceIndex + i)).Line;
// newInfo.BackgroundColor = Brushes.Red; << want to set the color like this.
I have tried solid brush but it does not seem to be working correctly.
You can Style the ListViewItem in xaml directly,
Example:
Assuming your "Name" variable is a string, you can try
<ListView Name="whatever">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Name}"
Value="John">
<Setter Property="Background"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
....
Now any ListView Row with "Name" Value of "John" will have a "Red" Background
an option
is to use IMultiValueConverter in ListView.ItemTemplate
<ListView DataContext="{Binding}" ItemsSource="{Binding Models}" AlternationCount="3" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name }"/>
<TextBlock Text="{Binding Desc }"/>
<StackPanel.Background>
<MultiBinding Converter="{StaticResource BackConverter}">
<Binding />
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}"/>
</MultiBinding>
</StackPanel.Background>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public class BackConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// write your logic (You have the model and the view model)
var index = ((ItemsControl)values[1]).Items.IndexOf(values[0]);
if (index % 2 == 0)
return Brushes.Gray;
return Brushes.White;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
another option
is to use ItemsControl.AlternationIndex in ListView.ItemContainerStyle
<ListView DataContext="{Binding}" ItemsSource="{Binding Models}" AlternationCount="3" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="Red" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="Green" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="2">
<Setter Property="Background" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Edit
public MainWindow()
{
InitializeComponent();
lv.ItemsSource = new List<string> { "a", "b", "c", "d", "e" };
}
After some googling i found out my own solution I am using Listview.ItemsSource and as source i use List with ListViewItems Then i can set background of specify ListViewItem in List, and just refresh listview.
XAML:
<ListView x:Name="listView" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Row="1">
<ListView.View>
<GridView>
<GridViewColumn Header="IP" DisplayMemberBinding="{Binding IP}" Width="Auto"/>
<GridViewColumn Header="PING" DisplayMemberBinding="{Binding Ping}" Width="Auto"/>
<GridViewColumn Header="Host Name" DisplayMemberBinding="{Binding DNS}" Width="Auto"/>
<GridViewColumn Header="Mac" DisplayMemberBinding="{Binding MAC}" Width="Auto"/>
<GridViewColumn Header="Výrobce" DisplayMemberBinding="{Binding Manufacturer}" Width="Auto"/>
</GridView>
</ListView.View>
</ListView>
Fill ListView with Items with Gray Background:
List<ListViewItem> ITEMS = new List<ListViewItem>();
private void button_Click(object sender, RoutedEventArgs e)
{
for (int i = 1; i < 20; i++)
{
ListViewItem OneItem = new ListViewItem();
OneItem.Background = Brushes.LightGray;
OneItem.Content = new Device() { IP = "1.1.1.1", Ping = "30ms", DNS = "XYZ", MAC = "2F:3C:5F:41:F9", Manufacturer = "Intel" };
ITEMS.Add(OneItem);
listView.ItemsSource = ITEMS;
}
listView.Items.Refresh();
}
public class Device
{
public string IP { get; set; }
public string Ping { get; set; }
public string DNS { get; set; }
public string MAC { get; set; }
public string Manufacturer { get; set; }
}
Create Method for Row Change Color:
private void ChangeRowColor(int RowIndex,SolidColorBrush NewBackground)
{
ITEMS[RowIndex].Background = NewBackground;
listView.Items.Refresh();
}
And use it:
private void button1_Click(object sender, RoutedEventArgs e)
{
ChangeRowColor(4, Brushes.Green);
}
I'm trying to create a WPF dialogue to configure a workshop schedule.
On the left side there is a listview with one column for the teachers' names.
On the right side there is a listview with six columns, one for workshops,
and the other five columns for the days from Monday to Friday.
| Teacher | | Workshop | Mon | Tue | Wed | Thu | Fri |
A WS-1 A B
B WS-2 C
C WS-3 B
The user should configure the schedule by drag and drop, e.g. teacher C teaches
workshop WS-2 on Monday.
In WinForms it was a simple job getting the drop cell, but I don't find a way
of getting this in WPF.
Here's a section of the xaml code.
<ListView Name="_LV_Teacher"
SelectionMode="Single"
ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn
DisplayMemberBinding="{Binding Path=Id}"
Width="0"/>
<GridViewColumn
DisplayMemberBinding="{Binding Path=TeachersName}" Header="Teacher"/>
</GridView>
</ListView.View>
</ListView>
<ListView Name="_LV_Schedule"
ItemsSource="{Binding}"
AlowDrop="True"
Drop="_LV_Teacher_Drop" >
<ListView.View>
<GridView>
<GridViewColumn
DisplayMemberBinding="{Binding Path=WorkshopId}" Width="0"/>
<GridViewColumn Header="Monday"/>
<GridViewColumn Header="Tuesday"/>
<GridViewColumn Header="Wednesday"/>
<GridViewColumn Header="Thursday"/>
<GridViewColumn Header="Friday"/>
</GridView>
</ListView.View>
</ListView>
DragDrop HowTo
Challange was to figure out which property should be used in DragDrop.DoDragDrop(). As we have different ListView , so using Teacher entity itself would be meaningful. I get the source Teacher from left side ListView using TextBlock.DataContext. And set it as DataContext of the Drop target TextBlock.
Issue was , which DataFormats value to use for DataContext, so I used IDataObject.GetFormats().
Output :
See the sample application below. You can simple copy/paste.
Window1.xaml
<Window x:Class="WpfStackOverflow.MyDragDrop.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfStackOverflow.MyDragDrop"
Title="Window1" Height="472.557" Width="675.564">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="123*"/>
<ColumnDefinition Width="380*"/>
</Grid.ColumnDefinitions>
<ListView Margin="10,31,10,226" ItemsSource="{Binding TeacherData}">
<ListView.Resources>
<Style x:Key="TbKey" TargetType="TextBlock">
<EventSetter Event="MouseLeftButtonDown" Handler="Teacher_LeftButtonDown"/>
<EventSetter Event="DragEnter" Handler="Teacher_DragEnter"/>
<Setter Property="Background" Value="Yellow"/>
<Setter Property="AllowDrop" Value="True"/>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Teachers" Width="75">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Width="{Binding View.Columns[0].Width, RelativeSource={RelativeSource AncestorType=ListView, Mode=FindAncestor}}"
Style="{StaticResource TbKey}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<ListView ItemsSource="{Binding AppointmentData}" Margin="13,31,10,226" Grid.Column="1" ScrollViewer.CanContentScroll="False">
<ListView.Resources>
<Style x:Key="TbKey" TargetType="TextBlock">
<EventSetter Event="MouseLeftButtonDown" Handler="WeekDay_LeftButtonDown"/>
<EventSetter Event="DragEnter" Handler="WeekDay_DragEnter"/>
<EventSetter Event="Drop" Handler="WeekDay_Drop"/>
<EventSetter Event="MouseRightButtonDown" Handler="WeekDay_MouseRightButtonDown"/>
<Setter Property="Background" Value="Yellow"/>
<Setter Property="AllowDrop" Value="True"/>
<Setter Property="DataContext" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext, RelativeSource={RelativeSource Self}}" Value="{x:Null}">
<Setter Property="Background" Value="{x:Null}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Workshop" Width="75">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Workshop}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn x:Name="ColMon" Header="Mon" Width="45">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding Mon, Mode=TwoWay}" Text="{Binding Name}" Width="{Binding View.Columns[1].Width, RelativeSource={RelativeSource AncestorType=ListView, Mode=FindAncestor}}"
Style="{StaticResource TbKey}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Tue" Width="45">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding Tue, Mode=TwoWay}" Text="{Binding Name}" Width="{Binding View.Columns[1].Width, RelativeSource={RelativeSource AncestorType=ListView, Mode=FindAncestor}}"
Style="{StaticResource TbKey}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Wed" Width="45">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding Wed, Mode=TwoWay}" Text="{Binding Name}" Width="{Binding View.Columns[1].Width, RelativeSource={RelativeSource AncestorType=ListView, Mode=FindAncestor}}"
Style="{StaticResource TbKey}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Thu" Width="45">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding Thu, Mode=TwoWay}" Text="{Binding Name}" Width="{Binding View.Columns[1].Width, RelativeSource={RelativeSource AncestorType=ListView, Mode=FindAncestor}}"
Style="{StaticResource TbKey}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Fri" Width="45">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding Fri, Mode=TwoWay}" Text="{Binding Name}" Width="{Binding View.Columns[1].Width, RelativeSource={RelativeSource AncestorType=ListView, Mode=FindAncestor}}"
Style="{StaticResource TbKey}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<DataGrid IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding AppointmentData}" Grid.Column="1" HorizontalAlignment="Stretch" Margin="13,243,0,0" VerticalAlignment="Top" >
<DataGrid.Columns>
<DataGridTextColumn Header="Worskhop" Binding="{Binding Workshop}" Width="*"/>
<DataGridTextColumn Header="Mon" Binding="{Binding Mon.Name}" Width="*"/>
<DataGridTextColumn Header="Tue" Binding="{Binding Tue.Name}" Width="*"/>
<DataGridTextColumn Header="Wed" Binding="{Binding Wed.Name}" Width="*"/>
<DataGridTextColumn Header="Thu" Binding="{Binding Thu.Name}" Width="*"/>
<DataGridTextColumn Header="Fri" Binding="{Binding Fri.Name}" Width="*"/>
</DataGrid.Columns>
</DataGrid>
<TextBlock Grid.Column="1" HorizontalAlignment="Left" Margin="13,222,0,0" TextWrapping="Wrap" Text="Real time display of workshop schedules" VerticalAlignment="Top" Width="325"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Left" Margin="13,10,0,0" TextWrapping="Wrap" Text="Right Click to remove appointment" VerticalAlignment="Top" Width="325"/>
</Grid>
</Window>
Window1.xaml.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfStackOverflow.MyDragDrop
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
ViewModel vm = new ViewModel();
public Window1()
{
InitializeComponent();
this.DataContext = vm;
}
#region WeekDay
private void WeekDay_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text))
e.Effects = DragDropEffects.Copy;
}
private void WeekDay_Drop(object sender, DragEventArgs e)
{
((TextBlock)sender).DataContext = e.Data.GetData(e.Data.GetFormats()[0]);
}
private void WeekDay_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
(sender as TextBlock).DataContext = null;
}
#endregion
#region Teacher
private void Teacher_LeftButtonDown(object sender, MouseButtonEventArgs e)
{
TextBlock tb = (TextBlock)sender;
DragDrop.DoDragDrop(tb, tb.DataContext, DragDropEffects.Copy | DragDropEffects.Move);
}
private void Teacher_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Serializable))
e.Effects = DragDropEffects.Copy;
}
#endregion
}
public class ViewModel : INotifyPropertyChanged
{
ObservableCollection<AppointmentRecord> _records = new ObservableCollection<AppointmentRecord>();
public ObservableCollection<AppointmentRecord> AppointmentData { get { return _records; } }
ObservableCollection<TeacherRecord> _teacherRecords = new ObservableCollection<TeacherRecord>();
public ObservableCollection<TeacherRecord> TeacherData { get { return _teacherRecords; } }
public ViewModel()
{
TeacherRecord trecord1 = new TeacherRecord() { Name = "A" };
TeacherRecord trecord2 = new TeacherRecord() { Name = "B" };
TeacherRecord trecord3 = new TeacherRecord() { Name = "C" };
TeacherData.Add(trecord1);
TeacherData.Add(trecord2);
TeacherData.Add(trecord3);
AppointmentRecord record1 = new AppointmentRecord() { Workshop = "WS-1", Mon = TeacherData.FirstOrDefault((t) => { return t.Name == "A"; }), Tue = null };
AppointmentRecord record2 = new AppointmentRecord() { Workshop = "WS-2", Mon = null, Tue = TeacherData.FirstOrDefault((t) => { return t.Name == "C"; }) };
AppointmentRecord record3 = new AppointmentRecord() { Workshop = "WS-3", Mon = null, Tue = null, Wed = TeacherData.FirstOrDefault((t) => { return t.Name == "C"; }) };
AppointmentData.Add(record1);
AppointmentData.Add(record2);
AppointmentData.Add(record3);
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public void OnPropertyChanged(string prop)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
public class TeacherRecord
{
public string Name { get; set; }
}
public class AppointmentRecord : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public void OnPropertyChanged(string prop)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
string _workshop;
public string Workshop
{
get { return _workshop; }
set
{
if (_workshop != value)
{
_workshop = value;
OnPropertyChanged("Workshop");
}
}
}
TeacherRecord _mon;
public TeacherRecord Mon
{
get { return _mon; }
set
{
if (_mon != value)
{
_mon = value;
OnPropertyChanged("Mon");
}
}
}
TeacherRecord _tue;
public TeacherRecord Tue
{
get { return _tue; }
set
{
if (_tue != value)
{
_tue = value;
OnPropertyChanged("Tue");
}
}
}
TeacherRecord _wed;
public TeacherRecord Wed
{
get { return _wed; }
set
{
if (_wed != value)
{
_wed = value;
OnPropertyChanged("Wed");
}
}
}
TeacherRecord _thu;
public TeacherRecord Thu
{
get { return _thu; }
set
{
if (_thu != value)
{
_thu = value;
OnPropertyChanged("Thu");
}
}
}
TeacherRecord _fri;
public TeacherRecord Fri
{
get { return _fri; }
set
{
if (_fri != value)
{
_fri = value;
OnPropertyChanged("Fri");
}
}
}
}
}
Thanks to AnjumSKhan for the excellent answer!
I've implemented it into my application, and it works fine. Unfortunately, I got another problem.
Because my data are retrieved and stored in a database, I added two variables:
- int iTeacherId to class TeacherRecord (first column with width 0 in the teacher's Listview), and
- int iWorkShopId to class AppointmentRecord (first column with width 0 in the AppointmentData-Listview)
Therefore, beside the teacher's name, e.Data in WeekDay_Drop now also contains his Id.
But how do I get the corresponding workshop Id in order to save appointment in Tab_Workshop in the database.
(The teacher's name and Id are in Tab_Teacher, a different database table.)
I have my object collection:
public class Data
{
string name {get; set;}
int progres {get; set;}
}
public ObservableCollection<Data> dataFiles { get; set; }
And my ListView:
<ListView Name="lvDataFiles"
ItemsSource="{Binding dataList}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Foreground" Value="White"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.Resources>
<DataTemplate x:Key="MyDataTemplate">
<Grid Margin="-6">
<ProgressBar Name="prog" Maximum="100" Value="{Binding Progress}"
Width="{Binding Path=Width, ElementName=ProgressCell}"
Height="16" Margin="0" Foreground="#FF5591E8" Background="#FF878889" />
<TextBlock Text="{Binding Path=Value, ElementName=prog, StringFormat={}{0}%}" VerticalAlignment="Center"
HorizontalAlignment="Center" FontSize="11" Foreground="White" />
</Grid>
</DataTemplate>
<ControlTemplate x:Key="ProgressBarTemplate">
<Label HorizontalAlignment="Center" VerticalAlignment="Center" />
</ControlTemplate>
</ListView.Resources>
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource ListViewHeaderStyle}">
<GridViewColumn Width="425" Header="File name" DisplayMemberBinding="{Binding FileName}" />
<GridViewColumn x:Name="ProgressCell" Width="50" Header="Progress"
CellTemplate="{StaticResource MyDataTemplate}" />
</GridView>
</ListView.View>
</ListView>
My ListView has 2 columns: file name and Progress (that contain progress bar)
My Data collection has the Progress property that changing every few seconds.
Is it possible that my ListView ProgressBar will update automatic each time specific object (or several in the same time..) changing ?
Or i need to go over my collection and update ?
Your Data class must inherit from INotifyPropertyChanged, add a NotifyPropertyChange method and call that for each setter.
public class Data : INotifyPropertyChanged
{
private string _name;
public string name
{
get { return _name; }
set
{
_name= value;
NotifyPropertyChanged("name");
}
}
private int _progress;
public int progress
{
get { return _progress; }
set
{
_progress = value;
NotifyPropertyChanged("progress");
}
}
public event PropertyChangedEventHandler PropertyChanged;
virtual public void NotifyPropertyChange( string propertyName )
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}