I'm trying to sort a ListView by it's headers.
I'm following this MSDN example, with the alternation given here - where this line works if I were to use direct binding:
GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
string sortString = ((Binding)headerClicked.Column.DisplayMemberBinding).Path.Path
But problem is I'm not binding the columns directly using DisplayMemberBinding="{Binding PVNum}" but rather I am using CellTemplate:
<ListView.Resources>
<DataTemplate x:Key="NumberTemplate">
<TextBlock Text="{Binding PVNum}" TextAlignment="Center" />
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridView.Columns>
<GridViewColumn Header=" " CellTemplate="{StaticResource NumberTemplate}"/>
</GridView.Columns>
</GridView>
</ListView.View>
So my question is - how do I get this "PVNum" string in the code behind?
I did try this, though s is null - so I guess I'm off:
var t = headerClicked.Column.CellTemplate.LoadContent() as TextBlock;
var s = t.GetBindingExpression(TextBox.TextProperty);
Any suggestions?
It should be TextBlock.Text property:
var t = headerClicked.Column.CellTemplate.LoadContent() as TextBlock;
var s = t.GetBindingExpression(TextBlock.TextProperty);
string sourcePropertyName = s.ParentBinding.Path.Path;
A possible solution is to define an attached property for GridViewColumn:
public class GridViewColumnAttachedProperties
{
public static readonly DependencyProperty SortPropertyNameProperty = DependencyProperty.RegisterAttached(
"SortPropertyName", typeof(string), typeof(GridViewColumnAttachedProperties), new PropertyMetadata(default(string)));
public static void SetSortPropertyName(DependencyObject element, string value)
{
element.SetValue(SortPropertyNameProperty, value);
}
public static string GetSortPropertyName(DependencyObject element)
{
return (string) element.GetValue(SortPropertyNameProperty);
}
}
In XAML you set the attached properties to the Path used in the Binding inside the templates. Based on the example from the MSDN site:
<ListView x:Name='lv' Height="150" HorizontalAlignment="Center" VerticalAlignment="Center" GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">
<ListView.Resources>
<DataTemplate x:Key="YearTemplate">
<TextBlock Text="{Binding Year}" TextAlignment="Center" />
</DataTemplate>
<DataTemplate x:Key="MonthTemplate">
<TextBlock Text="{Binding Month}" TextAlignment="Center" />
</DataTemplate>
<DataTemplate x:Key="DayTemplate">
<TextBlock Text="{Binding Day}" TextAlignment="Center" />
</DataTemplate>
</ListView.Resources>
<ListView.ItemsSource>
<collections:ArrayList>
<system:DateTime>1993/1/1 12:22:02</system:DateTime>
<system:DateTime>1993/1/2 13:2:01</system:DateTime>
<system:DateTime>1997/1/3 2:1:6</system:DateTime>
<system:DateTime>1997/1/4 13:6:55</system:DateTime>
<system:DateTime>1999/2/1 12:22:02</system:DateTime>
<system:DateTime>1998/2/2 13:2:01</system:DateTime>
<system:DateTime>2000/2/3 2:1:6</system:DateTime>
<system:DateTime>2002/2/4 13:6:55</system:DateTime>
<system:DateTime>2001/3/1 12:22:02</system:DateTime>
<system:DateTime>2006/3/2 13:2:01</system:DateTime>
<system:DateTime>2004/3/3 2:1:6</system:DateTime>
<system:DateTime>2004/3/4 13:6:55</system:DateTime>
</collections:ArrayList>
</ListView.ItemsSource>
<ListView.View>
<GridView>
<GridViewColumn CellTemplate="{StaticResource YearTemplate}" local:GridViewColumnAttachedProperties.SortPropertyName="Year" />
<GridViewColumn CellTemplate="{StaticResource MonthTemplate}" local:GridViewColumnAttachedProperties.SortPropertyName="Month" />
<GridViewColumn CellTemplate="{StaticResource DayTemplate}" local:GridViewColumnAttachedProperties.SortPropertyName="Day" />
</GridView>
</ListView.View>
</ListView>
And in the Click event handler you can just retrieve the value of the attached property with string bindingName = headerClicked.Column.GetValue(GridViewColumnAttachedProperties.SortPropertyNameProperty) as string;. Based on the MSDN example:
GridViewColumnHeader _lastHeaderClicked;
ListSortDirection _lastDirection = ListSortDirection.Ascending;
private void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e)
{
GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
if (headerClicked != null)
{
if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
{
ListSortDirection direction;
if (!ReferenceEquals(headerClicked, _lastHeaderClicked))
{
direction = ListSortDirection.Ascending;
}
else
{
if (_lastDirection == ListSortDirection.Ascending)
{
direction = ListSortDirection.Descending;
}
else
{
direction = ListSortDirection.Ascending;
}
}
string bindingName = headerClicked.Column.GetValue(GridViewColumnAttachedProperties.SortPropertyNameProperty) as string;
Sort(bindingName, direction);
if (direction == ListSortDirection.Ascending)
{
headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowUp"] as DataTemplate;
}
else
{
headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowDown"] as DataTemplate;
}
// Remove arrow from previously sorted header
if (_lastHeaderClicked != null && !ReferenceEquals(_lastHeaderClicked, headerClicked))
{
_lastHeaderClicked.Column.HeaderTemplate = null;
}
_lastHeaderClicked = headerClicked;
_lastDirection = direction;
}
}
}
private void Sort(string sortBy, ListSortDirection direction)
{
ICollectionView dataView = CollectionViewSource.GetDefaultView(lv.ItemsSource);
dataView.SortDescriptions.Clear();
SortDescription sd = new SortDescription(sortBy, direction);
dataView.SortDescriptions.Add(sd);
dataView.Refresh();
}
Related
I've got a problem with {Binding CurrentProgress} value of Progressbar control inside of a Listview. Within my code I'm able to add few items which has couple of properties with CurrentProgress property as well. Items are adding in a proper way, yet only ONE progressbar's updating. Here's the code:
MODEL:
sealed public class Mp3Model : INotifyPropertyChanged
{
public string Name { get; set; }
private double _currentProgress;
public double CurrentProgress
{
get
{
return _currentProgress;
}
set
{
_currentProgress = value;
OnPropertyChanged("CurrentProgress");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
<ListView ItemsSource="{Binding Mp3List}">
<ListView.View>
<GridView>
<GridViewColumn
Width="140"
DisplayMemberBinding="{Binding Name}"
Header="Track Name" />
<GridViewColumn Width="300" Header="Progress">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="320">
<ProgressBar
Height="40"
Margin="10"
IsIndeterminate="{Binding IsIndeterminate}"
Maximum="100"
Minimum="0"
Visibility="{Binding IsProgressDownloadVisible}"
Value="{Binding CurrentProgress}" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding CurrentProgress, StringFormat={}{0:0}%}"
Visibility="{Binding IsPercentLabelVisible}" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding ConvertingLabelText}"
Visibility="{Binding IsConvertingLabelVisible}" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding IsOperationDone}"
Visibility="{Binding IsOperationDoneLabelVisible}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
VIEW-MODEL (Method)
private void SaveVideoToDisk()
{
Task.Factory.StartNew(() =>
{
long currentLocalProgress = 0;
this._fileHelper = new FileHelper();
this._model = new Mp3Model();
using (var service = Client.For(YouTube.Default))
{
using (var video = service.GetVideo(YoutubeLinkUrl))
{
_fileHelper.DefaultTrackName = video.FullName;
_fileHelper.DefaultTrackPath = _fileHelper.Path + "\\" + _fileHelper.DefaultTrackName;
_fileHelper.DefaultTrackHiddenPath = _fileHelper.HiddenPath + "\\" + _fileHelper.DefaultTrackName;
_fileHelper.TmpTrackPath = _fileHelper.PreparePathForFFmpeg(_fileHelper.DefaultTrackHiddenPath);
_model = new Mp3Model()
{
Name = _fileHelper.DefaultTrackName,
IsProgressDownloadVisible = Visibility.Visible,
IsPercentLabelVisible = Visibility.Visible,
IsConvertingLabelVisible = Visibility.Hidden,
IsOperationDoneLabelVisible = Visibility.Hidden,
ConvertingLabelText = Consts.ConvertingPleaseWait,
CurrentProgress = 0,
};
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
this._mp3List.Add(_model);
}));
using (var outFile = File.OpenWrite(_fileHelper.TmpTrackPath))
{
using (var progressStream = new ProgressStream(outFile))
{
var streamLength = (long)video.StreamLength();
progressStream.BytesMoved += (sender, args) =>
{
currentLocalProgress = args.StreamLength * 100 / streamLength;
_model.CurrentProgress = currentLocalProgress;
Debug.WriteLine($"{_model.CurrentProgress}% of video downloaded");
};
video.Stream().CopyTo(progressStream);
}
}
//ExtractAudioFromVideo(_fileHelper.TmpTrackPath);
}
}
});
}
Place of the ProgressBar Binded value:
progressStream.BytesMoved += (sender, args) =>
{
currentLocalProgress = args.StreamLength * 100 / streamLength;
_model.CurrentProgress = currentLocalProgress;
Debug.WriteLine($"{_model.CurrentProgress}% of video downloaded");
};
Does anyone has any idea?
Trying to guess: you update a _model field which will be overriden each time you call the save video to disk method. This may only work if only one call of this method can be done by instance of the class (but as we don't have the clas, we don't know if it's the list or the video).
So I would say that invoking twice the method stops the first _model instance from being updated (as the lambda captures the variable holding the object)
xaml looks okey to me, but I had similar problems, I fixed as follows:
add Mode=OneWay to the Value="{Binding CurrentProgress, Mode=OneWay}".
Also whenever you update CurrentProgress use the Dispatcher: Application.Current.Dispatcher.Invoke(() => CurrentProgress++);
I hope it can helps you to find the solution.
Edit: Just a suggestion, I use the following OnPropertyChanged, so you don't have to write the name of the properties everytime =D.
protected void OnPropertyChange([CallerMemberName] string inPropertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(inPropertyName));
I have a RadTreeView (treeview) and a RadGridView (gridview). The user should be able to move elements from the gridview to the treeview and change the effect of the drag&drop action by using the shift or control key (like in Windows Explorer).
In the GiveFeedback event the effect is set according to the pressed key and also the visualization shows the expected behavior. But in the Drop event (on the treeview) and in the DragDropCompleted event (on the gridview) the effect is set to All, therefore I'm not able to decide if I have to remove the Element from the current list.
Am I missing something?
XAML:
<telerik:RadTreeView AllowDrop="True"
ItemsSource="{Binding Folders}"
SelectedItem="{Binding SelectedFolder,
Mode=TwoWay}"
SelectionMode="Single">
<telerik:RadTreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Folder}" ItemsSource="{Binding Children}">
<Grid VerticalAlignment="Center">
<TextBlock VerticalAlignment="Center"
Text="{Binding Name}"
local:TreeItemDropBehavior.IsEnabled="True" />
</Grid>
</HierarchicalDataTemplate>
</telerik:RadTreeView.Resources>
</telerik:RadTreeView>
<telerik:RadGridView Grid.Column="1"
AllowDrop="True"
AutoGenerateColumns="False"
CanUserFreezeColumns="False"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
FontSize="12"
IsFilteringAllowed="False"
IsReadOnly="True"
ItemsSource="{Binding SelectedFolder.Elements}"
RowHeight="32"
RowIndicatorVisibility="Collapsed"
SelectionMode="Multiple"
ShowGroupPanel="False"
local:GridViewDragDropBehavior.IsEnabled="True"
telerik:DragDropManager.AllowCapturedDrag="True"
telerik:DragDropManager.AllowDrag="True">
<telerik:RadGridView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<DataTemplate x:Key="DraggedItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Dragging: " />
<TextBlock FontWeight="Bold" Text="{Binding CurrentDraggedItems.Count}" />
<TextBlock Text=" Element(s)" />
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</telerik:RadGridView.Resources>
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Width="100"
DataMemberBinding="{Binding Name}"
Header="Name" />
<telerik:GridViewDataColumn Width="250"
DataMemberBinding="{Binding Description}"
Header="Description" />
</telerik:RadGridView.Columns>
</telerik:RadGridView>
GridViewDragDropBehavior:
public class GridViewDragDropBehavior
{
public RadGridView AssociatedControl { get; set; }
private void SubscribeToDragDropEvents()
{
DragDropManager.AddDragInitializeHandler(AssociatedControl, OnDragInitialize);
DragDropManager.AddGiveFeedbackHandler(AssociatedControl, OnGiveFeedback);
DragDropManager.AddDragDropCompletedHandler(AssociatedControl, OnDragDropCompleted);
DragDropManager.AddDragOverHandler(AssociatedControl, OnDragOver);
}
private void UnsubscribeFromDragDropEvents()
{
DragDropManager.RemoveDragInitializeHandler(AssociatedControl, OnDragInitialize);
DragDropManager.RemoveGiveFeedbackHandler(AssociatedControl, OnGiveFeedback);
DragDropManager.RemoveDragDropCompletedHandler(AssociatedControl, OnDragDropCompleted);
DragDropManager.RemoveDragOverHandler(AssociatedControl, OnDragOver);
}
private void OnDragInitialize(object sender, DragInitializeEventArgs e)
{
DropIndicationDetails details = new DropIndicationDetails();
var gridView = sender as RadGridView;
details.DragSource = gridView.ItemsSource;
var items = gridView.SelectedItems;
details.CurrentDraggedItems = items;
IDragPayload dragPayload = DragDropPayloadManager.GeneratePayload(null);
dragPayload.SetData("DraggedData", items);
dragPayload.SetData("DropDetails", details);
e.Data = dragPayload;
e.DragVisual = new DragVisual { Content = details, ContentTemplate = AssociatedControl.Resources["DraggedItemTemplate"] as DataTemplate };
e.DragVisualOffset = new Point(e.RelativeStartPoint.X + 10, e.RelativeStartPoint.Y);
e.AllowedEffects = DragDropEffects.All;
}
private void OnGiveFeedback(object sender, GiveFeedbackEventArgs e)
{
Debug.WriteLine("GridViewDragDropBehavior.OnGiveFeedback {0}", e.Effects);
e.SetCursor(Cursors.Arrow);
e.Handled = true;
}
private void OnDragDropCompleted(object sender, DragDropCompletedEventArgs e)
{
Debug.WriteLine("GridViewDragDropBehavior.OnDragDropCompleted: {0}", e.Effects);
var data = DragDropPayloadManager.GetDataFromObject(e.Data, "DraggedData") as IList;
var details = DragDropPayloadManager.GetDataFromObject(e.Data, "DropDetails");
Debug.WriteLine(e.Effects);
// Remove Element from source list if drag drop effect is move
/*if (e.Effects == DragDropEffects.Move)
{
var collection = (details as DropIndicationDetails).DragSource as IList;
foreach(var element in data)
{
collection.Remove(element);
}
}*/
}
private void OnDragOver(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
{
Debug.WriteLine("GridViewDragDropBehavior.OnDragOver: {0}", e.Effects);
e.Effects = DragDropEffects.None;
e.Handled = true;
}
}
TreeItemDropBehavior.cs:
public class TreeItemDropBehavior
{
protected virtual void Initialize()
{
DragDropManager.AddGiveFeedbackHandler(AssociatedObject, OnGiveFeedback);
DragDropManager.AddDropHandler(AssociatedObject, OnDrop);
}
protected virtual void CleanUp()
{
DragDropManager.RemoveGiveFeedbackHandler(AssociatedObject, OnGiveFeedback);
DragDropManager.RemoveDropHandler(AssociatedObject, OnDrop);
}
private void OnGiveFeedback(object sender, Telerik.Windows.DragDrop.GiveFeedbackEventArgs e)
{
Debug.WriteLine("TreeItemDropBehavior.OnGiveFeedback {0}", e.Effects);
e.SetCursor(Cursors.Arrow);
e.Handled = true;
}
private void OnDrop(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
{
Debug.WriteLine("TreeItemDropBehavior.OnDrop: {0}", e.Effects);
if (e.Effects != DragDropEffects.None)
{
var destinationItem = (e.OriginalSource as FrameworkElement).ParentOfType<RadTreeViewItem>();
var data = DragDropPayloadManager.GetDataFromObject(e.Data, "DraggedData") as IList;
var details = DragDropPayloadManager.GetDataFromObject(e.Data, "DropDetails") as DropIndicationDetails;
if (destinationItem != null)
{
foreach (var element in data)
{
(destinationItem.DataContext as Folder).Elements.Add(element as Element);
}
e.Handled = true;
}
}
}
}
I am trying to make a simple download manager, I am having trouble with adding a column with ProgressBars, it creates two columns with the same value but one has
numeric and one has progressbar values. How can I make "Progress1" be hidden or remove it but still keep the values in "Progress2"
Here is the main xaml
<DataGrid.Columns>
<!--#region Program Number -->
<DataGridTemplateColumn SortMemberPath="#" Header="#">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBlock Text="{Binding ProgramID}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<!--#endregion-->
<!--#region Program Number -->
<DataGridTemplateColumn SortMemberPath="Name" Header="Name">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<!--#endregion-->
<!--#region Program Number -->
<DataGridTemplateColumn SortMemberPath="Size" Header="Size">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBlock Text="{Binding Size}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<!--#endregion-->
<!--#region Progress bar columns -->
<DataGridTemplateColumn SortMemberPath="Progress"
Header="Progress" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ProgressBar Value="{Binding Progress}"
Height="15"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!--#endregion-->
</DataGrid.Columns>
</DataGrid>
Here is the Code-Behind of the programs
public class Programs : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnProperyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
private int _programid;
public int ProgramID
{
get { return _programid; }
set
{
_programid = value;
OnProperyChanged($"{nameof(ProgramID)}");
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnProperyChanged($"{nameof(Name)}");
}
}
private double _size;
public double Size
{
get { return _size; }
set
{
_size = value;
OnProperyChanged($"{nameof(Size)}");
}
}
private double _progress;
public double Progress
{
get { return _progress; }
set
{
_progress = value;
OnProperyChanged($"{nameof(Progress)}");
}
}
public ObservableCollection<Programs> ProgramList()
{
ObservableCollection<Programs> programs = new ObservableCollection<Programs>
{
new Programs { _programid = 1, _name = "Program0", _size = 5.1, _progress = 100 },
new Programs { _programid = 2, _name = "Program1", _size = 7.1, _progress = 36.7 },
new Programs { _programid = 3, _name = "Program2", _size = 1.1, _progress = 44.7 },
new Programs { _programid = 4, _name = "Program3", _size = 6.1, _progress = 88.7 },
new Programs { _programid = 5, _name = "Program4", _size = 2.1, _progress = 89.7 },
new Programs { _programid = 6, _name = "Program5", _size = 9.1, _progress = 68.7 },
new Programs { _programid = 7, _name = "Program6", _size = 5.1, _progress = 98.7 },
new Programs { _programid = 8, _name = "Program7", _size = 2.1, _progress = 59.7 },
new Programs { _programid = 9, _name = "Program8", _size = 83.1, _progress = 18.7 }
};
return programs;
}
}
Here is what it look like
(First time posting a question so if anything is missing I'll be glad to add)
The problem is the columns are getting auto generated because you have not set AutoGeneratedColumns="false" and true is the default.
When you don't set it to false the DataGrid will generate a column for each property in the assigned viewmodel.
For more information have a look at DataGrid.AutoGenerateColumns Property
When you set it to false you'll only see the progress bar. So you have to specifiy the other columns like you did it with the ProgressBar.
You could it like this
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ProgramID}"/>
<DataGridTextColumn Binding="{Binding Name}"/>
<DataGridTextColumn Binding="{Binding Size}"/>
<DataGridTemplateColumn SortMemberPath="Progress" Header="Progress2">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ProgressBar Value="{Binding Progress1}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
edit
Use DataGridTextColumn like this
<DataGridTextColumn SortMemberPath="ProgramID"
Header="#"
Binding="{Binding ProgramID}"/>
instead of a TemplateColumn when you want to show text. Much easier ;)
The problem why you won't see anything with your code is hat you only set the
CellEditingTemplate and not the CellTemplate.
The CellEditingTemplate is the template which will be shown when the cell is in edit mode.
The CellTemplate is the one which will be shown when the cell isn't in edit mode.
When you wan't to do it your way you have to change this like
<DataGridTemplateColumn SortMemberPath="ProgramID" Header="#">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ProgramID}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I am new to MVVM I have scenario I have One textbox and One Listview .When textbox text(PONo) changed , the listview get populated with some data (PORecords) by filtering through the text.
My View is:
<TextBox Height="24"
VerticalAlignment="Top"
Width="119"
Text="{Binding Path=PONo,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
/>
<ListView Height="161"
ItemsSource="{Binding Path=PORecords}"
SelectedItem="{Binding Path=SelectedPO,Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True"
Visibility="{Binding Path=PORecords,Converter={StaticResource ResourceKey=NullToVisibilityConverter}}"
Width="357">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=PurchaseOrderRefNo}"
Header="Order No"
Width="100" />
<GridViewColumn DisplayMemberBinding="{Binding Path=OrderDate, StringFormat=dd-MMM-yyyy}"
Header="Order Date"
Width="100" />
</GridView>
</ListView.View>
</ListView>
My ViewModel is:
private string _pONo;
public string PONo
{
get { return _pONo; }
set
{
if (value != "" && value!=null)
{
_pONo = value;
List<Tbl_PurchaseOrderMain> _lst = new List<Tbl_PurchaseOrderMain>();
_lst = new Tbl_PurchaseOrderMain().Select(" PurchaseOrderRefNo like '" + _pONo + "%'");
if (_lst.Count != 0)
{
PORecords = _lst;
}
else
{
PORecords = null;
}
}
else
{
PORecords = null;
}
RaisePropertyChanged("PONo");
}
}
private List<Tbl_PurchaseOrderMain> _pORecords;
public List<Tbl_PurchaseOrderMain> PORecords
{
get { return _pORecords; }
set
{
_pORecords = value;
RaisePropertyChanged("PORecords");
}
}
private Tbl_PurchaseOrderMain _selectedPO;
public Tbl_PurchaseOrderMain SelectedPO
{
get { return _selectedPO; }
set
{
_selectedPO = value;
if (SelectedPO != null)
{
PONo = SelectedPO.PurchaseOrderRefNo;
}
else
{
PONo = null;
}
RaisePropertyChanged("SelectedPO");
}
}
My problem is that when I enter text on textbox it will populate the listview (PORecords) with three Items.On that moment the selectedPO property is also fired then the textBox is filled the PONo but my listview then have only one Item the other two item gone .Actually I dont select any item on the Listview.I want to populate the textbox only when I select an Item from the listview whats wrong with my code any body have idea?
I have some problems finding the right TextBlock control inside a StackPanel.
My markup:
<ListBox Name="lstTimeline" ItemContainerStyle="{StaticResource TwItemStyle}"
MouseDoubleClick="lstTimeline_MouseDoubleClick">
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel MaxWidth="{Binding ElementName=lstTimeline, Path=ActualWidth}">
<Border Margin="10" DockPanel.Dock="Left" BorderBrush="White"
BorderThickness="1" Height="48" Width="48" HorizontalAlignment="Center">
<Image Source="{Binding ThumbNail, IsAsync=True}" Height="48" Width="48" />
</Border>
<StackPanel Name="stkPanel" Margin="10" DockPanel.Dock="Right">
<TextBlock Text="{Binding UserName}" FontWeight="Bold" FontSize="18" />
<TextBlock Text="{Binding Text}" Margin="0,4,0,0" FontSize="14"
Foreground="#c6de96" TextWrapping="WrapWithOverflow" />
<TextBlock Text="{Binding ApproximateTime}" FontSize="14"
FontFamily="Georgia" FontStyle="Italic" Foreground="#BBB" />
<TextBlock Text="{Binding ScreenName}" Name="lblScreenName" FontSize="14"
FontFamily="Georgia" FontStyle="Italic" Foreground="#BBB"
Loaded="lblScreenName_Loaded" />
</StackPanel>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My double click code:
private void lstTimeline_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
ListBoxItem lbi = (lstTimeline.SelectedItem as ListBoxItem);
StackPanel item = lbi.FindName("stkPanel") as StackPanel;
if (item != null)
MessageBox.Show("StackPanel null");
TextBlock textBox = item.FindName("lblScreenName") as TextBlock;
if (textBox != null)
MessageBox.Show("TextBlock null");
MessageBox.Show(textBox.Text);
}
But the StackPanel is null. How do find the right TextBlock in SelectedItem?
Thanks for your help.
ListBoxItem myListBoxItem = (ListBoxItem)(lstUniqueIds.ItemContainerGenerator.ContainerFromIndex(lstUniqueIds.SelectedIndex));
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(myListBoxItem);
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
CheckBox target = (CheckBox)myDataTemplate.FindName("chkUniqueId", myContentPresenter);
if (target.IsChecked)
{
target.IsChecked = false;
}
else
{
target.IsChecked = true;
}
Function FindVisualChild can be found on the MSDN page FrameworkTemplate.FindName Method:
private childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
There's a specific function to use when you're looking for something whose name is defined in a template. Try it like this:
private void lstTimeline_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
ListBoxItem lbi = (lstTimeline.SelectedItem as ListBoxItem);
StackPanel item = Template.FindName("stkPanel",lbi) as StackPanel;
if (item != null)
MessageBox.Show("StackPanel null");
TextBlock textBox = Template.FindName("lblScreenName",item) as TextBlock;
if (textBox != null)
MessageBox.Show("TextBlock null");
MessageBox.Show(textBox.Text);
}
Linq to xml with a get and set model.
var item = ...
lstTimeline.SelectedIndex = -1;
lstTimeline.ItemsSource = item;