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?
Related
My Situation:
I'm trying to affect a label from one TabItem of a TabControl by clicking a Button on another TabItem of the same TabControl.
I'm currently having a hard time figuring out why the property of my TextBox textBoxTyp won't change its value even after updating the property. The binding is correct an a button right next to the TextBox (on the same TabItem) that's bound exactly like the other Button from the other `Tabitem, works perfectly fine. I'm using the MVVM pattern and databinding.
Here the code of the TabControl itself
<TabControl Name="TabSpaces"
SelectedIndex="{Binding TabIndex, Mode=TwoWay, Source={StaticResource vm_Für_Typenschild}}"
Background="White" Margin="0,0,0,-4">
<TabItem DataContext="{Binding TypneschildVM, Source={StaticResource vm_Für_Typenschild}}"
FontSize="15" Foreground="White" FontWeight="Bold" Background="#401746"
Header="Datei" Margin="0,0,-60,0">
<view:DateiV/>
</TabItem>
<TabItem MouseLeftButtonDown="SelectedTypenschild" Loaded="Typenschild_Loaded"
FontSize="15" Height="50" Foreground="White" FontWeight="Bold"
Background="#401746" Header="Typenschild" BorderBrush="#FFACACAC"
Margin="56,0,-128,0">
<view:TypenschildVM Width="Auto" Height="Auto" HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch" Margin="1,0"/>
</TabItem>
</TabControl>
Here the code from the view of the TabItem with the button that should affect the TextBox
<Button Command="{Binding ReadXmlAndInsertIntoDialogsIntoTypenSchild_Command, Source={StaticResource vm_Für_Typenschild}}"
FontSize="25" x:Name="button_Datei_entfernen" Foreground="White"
Content="Datei entfernen" HorizontalAlignment="Center" Margin="476,468,476,215"
VerticalAlignment="Center" Width="326" Height="70">
</Button>
Here the code from the functions that should change the property ( ReadXmlAndInsertIntoDialogsIntoTypenSchild & CompareXmlWithJsonAndInsertIntoDialog )
namespace WPF_App_RFID_SpinOff.ViewModel
{
public class TypneschildVM : INotifyPropertyChanged, ICommand
{
private string CompareXmlWithJsonAndInsertIntoDialog(string XmlFileStringToCheck, string IdFromJsonFile)
{
string ValueTopass = "";
string line = "";
StringReader StringReaderOfXmlFile = new StringReader(XmlFileStringToCheck);
while ((line = StringReaderOfXmlFile.ReadLine()) != null)
{
if (line.Contains(IdFromJsonFile) == true)
{
int IndexRightNow = line.IndexOf('V');
int IndexWhereValueStart = line.IndexOf('V');
int CounterToGetValue = 0;
for (CounterToGetValue = IndexWhereValueStart + 1; CounterToGetValue < line.Length; CounterToGetValue++)
{
if (line[CounterToGetValue] != '"' && line[CounterToGetValue] != '=' && line[CounterToGetValue] != '/' && line[CounterToGetValue] != '>')
{
ValueTopass += line[CounterToGetValue];
}
}
}
}
return ValueTopass;
// Console.WriteLine(TypenschildM_ToUse.Hardwareversion);
}
public void ReadXmlAndInsertIntoDialogsIntoTypenSchild(object parameter)
{
int OpenBracketCount = 0;
string IdFromJsonFile = "";
string StringOfJsonFile = StaticFunc.ProvideJsonFile();
string StringOfXmlFile = StaticFunc.ProvideXMLFile();
string StringOfInformationforTypenschildFromXml = GetPartOfXmlFileForTypenSchild(StringOfXmlFile);
string StringOfInformationforTypenschildFromJson = GetPartOfJsonFileForTypenSchild(StringOfJsonFile);
string BlockOfDataforCertainValue = " ";
Console.WriteLine("test");
foreach (char character in StringOfJsonFile)
{
if (character == '{')
{
OpenBracketCount++;
}
if (OpenBracketCount >= 1)
{
BlockOfDataforCertainValue += character;
if (character == '}')
{
Console.WriteLine(BlockOfDataforCertainValue);
IdFromJsonFile = lookOutForID(BlockOfDataforCertainValue);
PropTest = CompareXmlWithJsonAndInsertIntoDialog(StringOfXmlFile, IdFromJsonFile);
OnPropertyChanged("PropTest");
}
}
}
}
#region ICommandSchnittstelle
public bool CanExecute(object parameter)
{
throw new NotImplementedException();
}
public void Execute(object parameter)
{
throw new NotImplementedException();
}
#endregion
public TypneschildVM()
{
TypenschildM TypenschildM_ToUse = TypenschildM.Instance;
LeseXMLAus = new RelayCommand(ReadXMLFileForTypenschildVM, StaticFunc.enableExecute);
ReadXmlAndInsertIntoDialogsIntoTypenSchild_Command = new RelayCommand(ReadXmlAndInsertIntoDialogsIntoTypenSchild, StaticFunc.enableExecute);
startButtoon_Command = new RelayCommand(ReadXmlAndInsertIntoDialogsIntoTypenSchild, StaticFunc.enableExecute);
}
}
}
Heres The Binding of my Textbox
<TextBox IsReadOnly="True"
Text="{Binding PropTest, Source={StaticResource vm_Für_Typenschild}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
x:Name="textBoxTyp" Height="22" Margin="243,93,133,0" TextWrapping="Wrap"
VerticalAlignment="Top" Background="#FFF3F3F3" Grid.Column="2"/>
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'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();
}
here i m using a wpf ComboBox control and binding it using the datasource.
but my combobox is unable to set default seletion of first index which i give
manualy during the time to binding. here my code shown below can any one tell me how to set default item in combox box.
//Xaml
<ComboBox Height="23" HorizontalAlignment="Left" Margin="142,11,0,0" Name="cmbProductType" VerticalAlignment="Top" Width="180" ItemsSource="{Binding}" />
//Code
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ClsControl.GetProductTypeList(cmbProductType);
}
public static void GetProductTypeList(ComboBox ddlProductType)//Add By Sandeep On 11-03-2013
{
try
{
DataTable dtProductType = null;
try
{
ClsDataLayer objDataLayer = new ClsDataLayer();
dtProductType = objDataLayer.ExecuteDataTable("COMNODE_PROC_GetProductTypeList");
if (dtProductType != null && dtProductType.Rows.Count > 0)
{
DataRow drCardType = dtProductType.NewRow();
drCardType[0] = -1;
drCardType[1] = "< -- Select Card Type -- >";
ddlProductType.SelectedValue = -1;
dtProductType.Rows.InsertAt(drCardType, 0);
ddlProductType.ItemsSource = dtProductType.DefaultView;
ddlProductType.DisplayMemberPath = "PRODUCT_TYPE";
ddlProductType.SelectedValuePath = "PRODUCT_TYPE_ID";
}
}
catch (Exception)
{
throw;
}
}
catch
{
}
}
Try updating your XAML to this:
<ComboBox Height="23"
HorizontalAlignment="Left"
Margin="142,11,0,0"
Name="cmbProductType"
VerticalAlignment="Top"
Width="180"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True" />
Also, use SelectedIndex instead when you select the item:
ddlProductType.SelectedIndex = 0;
dtProductType.Rows.InsertAt(drCardType, 0);
ddlProductType.ItemsSource = dtProductType.DefaultView;
ddlProductType.DisplayMemberPath = "PRODUCT_TYPE";
ddlProductType.SelectedValuePath = "PRODUCT_TYPE_ID"
So despite finding articles online I still cannot figure this out.
I have a Listbox
<ListBox HorizontalAlignment="Left" Margin="54,35,0,0" Name="resultsbox" VerticalAlignment="Top" Width="382" Visibility="Collapsed">
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding nameElement}"/>
</StackPanel>
</DataTemplate>
</ListBox>
That is databound to
ObservableCollection<string> results = new ObservableCollection<string>();
and is updated with
private void searchbox_TextChanged(object sender, TextChangedEventArgs e)
{
resultsbox.Visibility = Visibility.Visible;
resultsbox.ItemsSource = results;
if (results.Count == 0)
{
foreach (ele item in eles)
{
if (!results.Contains(item.nameElement))
{
results.Add(item.nameElement);
}
}
}
else
{
resultsbox.Items.Clear();
}
if (searchbox.Text.Equals(""))
{
window1.Height = 47;
resultsbox.Visibility = Visibility.Collapsed;
}
if (resultsbox.Items.Count == 0)
{
resultsbox.Visibility = Visibility.Collapsed;
window1.Height = 47;
}
else{
window1.Height = 47 + (22 * resultsbox.Items.Count);
}
}
It loads ALL the data in there but WILL NOT UPDATE!
If I do resultsbox.clear() it says you can't clear bound items. If you try and clear the source it does nothing. If you try and set the resultsbox itemsource to null and clear the source then rebind it, nothing. If you try and bind the listbox to an empty source it does nothing....
The answer was changing the foreach loop in the update from
resultsbox.ItemsSource = results;
if (results.Count == 0)
{
foreach (ele item in eles)
{
if (!results.Contains(item.nameElement))
{
results.Add(item.nameElement);
}
}
}
to
results.Clear();
foreach (ele item in eles)
{
if (item.nameElement.ToLower().Contains(searchbox.Text.ToLower()))
{
results.Add(item.nameElement);
}
}
resultsbox.ItemsSource = results;
You can try using Two-Way Mode Binding to achieve your requirement IMO,
<ListBox HorizontalAlignment="Left" Margin="54,35,0,0" Name="resultsbox" VerticalAlignment="Top" Width="382" Visibility="Collapsed">
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding nameElement, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>