Binding a Path in the class to an int property - wpf

I would like to bind a property in the source data to an int. Take for instance:
<ComboBox Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" ItemsSource="{Binding Makes}" SelectedItem="{Binding Path=Make_ID}" DisplayMemberPath="MakeDesc" />
From the ViewModel:
public short Make_ID { get { return Vehicle.Make_ID; } set { Vehicle.Make_ID = value; OnPropertyChanged("Make_ID"); } }
Makes is a class that has ID, MakeDesc, etc. My View Model is interested in the selected make but only it's ID. I know I could do this with IValueConverters but I'd rather not have to do that -- I think there is a way to do that on the binding, I just can't remember how.

The answer is to use SelectedValue and SelectedPath instead.
<ComboBox Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" ItemsSource="{Binding Makes}" SelectedValue="{Binding Path=Make_ID}" SelectedValuePath="ID" DisplayMemberPath="MakeDesc" />

Related

WPF XAML ListBox bind to array

So i have a float array which i want to have as ItemSource in a ListBox.
Inside the ItemTemplate i have a progress bar, that should bind its Progress value to the given float value. Yet i can't ever see that the values are actually bound to the Progress property.
The xaml code (i don't know whether i'm wrong but i expected that there's a implicit cast from float to double):
<ListBox ItemsSource="{Binding CoreLoads, Mode=OneWay}" BorderThickness="0">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type sys:Double}">
<StackPanel>
<ctrl:MetroProgressBar Orientation="Vertical" Progress="{Binding}" ExtenedBorderWidth="0.2" Width="30" Height="50" VerticalAlignment="Center"
HorizontalAlignment="Center" BorderBrush="Black" BorderThickness="2" Background="White" Margin="5"/>
<TextBlock Margin="0,3,0,3" HorizontalAlignment="Center" Text="{Binding LastUpdateTime, StringFormat='{}{0:hh:mm:ss tt}', Mode=OneWay}"
DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
xmlns:sys="clr-namespace:System;assembly=mscorlib"
and the property itself:
public double[] CoreLoads
{
get { return cpuManagement.ProcessorInfo.LoadPercentages; }
}
Note: The progress bar i'm using is a custom control and inherits from System.Windows.Controls.Control.
Problem seems to be that the values of the array are ok but when bound to a TextBlock the values are 0, so the progress of the progress bar is always 0. So, am i having a correct data template for a double array? Or should i change to another type of collection?
I guess you should create a property in a ViewModel(assuming you're using MVVM pattern) which will represent selected value of the ListBox:
private double selectedCoreLoad;
public Double SelectedCoreLoad
{
get
{
return selectedCoreLoad;
}
set
{
if (selectedCoreLoad != value)
{
selectedCoreLoad = value;
RaisePropertyChanged("SelectedCoreLoad");
}
}
}
Then, you should bind selected value of the ListBox to this property:
<ListBox ItemsSource="{Binding CoreLoads, Mode=OneWay}" SelectedValue="{Binding SelectedCoreLoad, Mode=TwoWay}" BorderThickness="0">
<ctrl:MetroProgressBar Orientation="Vertical" Progress="{Binding SelectedCoreLoad}" ExtenedBorderWidth="0.2" Width="30" Height="50" VerticalAlignment="Center"
HorizontalAlignment="Center" BorderBrush="Black" BorderThickness="2" Background="White" Margin="5"/>
UPD
Use ObservableCollection instead:
private ObservableCollection<Double> coreLoads;
public ObservableCollection<Double> CoreLoads
{
get { return coreLoads; }
set
{
coreLoads = value;
RaisePropertyChanged("CoreLoads");
}
}
So found the answer: ListBox seems not to like arrays as ItemsSource. After changing the source to a double-list everything works.
public List<double> CoreLoads
{
get { return new List<double>(cpuManagement.ProcessorInfo.LoadPercentages); }
}

Trying to bind datatable with listbox...something wrong

Please help...what am I doing wrong here? Trying to bind listbox to datatable. After debugging, i see data rows in the table but some how it is not binding to listbox.
FYI. _this is the name of my current window...
<ListBox Grid.Column="1" ItemsSource="{Binding ElementName=_this, Path=MainCategoriesTable}" HorizontalAlignment="Center" BorderBrush="Transparent" Background="Transparent" x:Name="lbMainCategories">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<RadioButton Grid.Column="0" Content="{Binding Path=main_category_name}" VerticalAlignment="Center" GroupName="grpMainCategory" x:Name="rdbEnableDisable" />
<Label Grid.Column="1" Width="30" Background="Transparent" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Below is the property trying to bind with...
public DataTable MainCategoriesTable
{
get { return _dtMainCategory; }
set { _dtMainCategory = value; }
}
For XAML to set the data context tocode behind this is what works for me
DataContext="{Binding RelativeSource={RelativeSource Self}}"
in code behind
this.DataContext = this;
But I used _this like you have used it successfully.
Set Presentation.Trace = High in the all XAML binding. That is not the exact syntax but if you start with Presentation it should be obvious.
Why no binding on label.
main_category_name is a public property? I notice it is in lower case.
DataTable works like a dictionary, not like an object. It doesn't expose your columns as properties, but each DataRow exposes an indexer that can be used to get the cell value. Therefore, you need to use indexer syntax:
<RadioButton Grid.Column="0" Content="{Binding Path=[main_category_name]}" VerticalAlignment="Center" GroupName="grpMainCategory" x:Name="rdbEnableDisable" />
UPDATE
Another thing that bothers me is that your MainCategoriesTable property doesn't notify about changes. If it's changed after all Bindings have been initialized, it won't work (while DependencyProperty will, because it always notifies about changes). To make it work, your context class must implement INotifyPropertyChanged interface and your property must look like this:
public DataTable MainCategoriesTable
{
get { return _dtMainCategory; }
set
{
if(value == _dtMainCategory)
{
return;
}
_dtMainCategory = value;
var h = this.PropertyChanged;
if(h != null)
{
h(this, new PropertyChangedEventArgs("MainCategoriesTable"));
}
}
}

ObservableCollection Images in Listbox to Content Control master detail WPf

I have an observablecollection of Images that get populated via the following code:
<StackPanel Orientation="Horizontal" Grid.Column="0">
<ListBox ItemsSource="{Binding BigImageView}" IsSynchronizedWithCurrentItem="True"
SelectedIndex="0" SelectedItem="{Binding CurrentItem}" />
</StackPanel>
<ContentControl Name="Detail" Content="{Binding BigImageView, Mode=OneWay}"
Margin="9,0,0,0" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"/>
However the Content Control is supposed to bind to the BigImageView via an ObservableCollection
BigImage = new ObservableCollection<Image>();
_listView = CollectionViewSource.GetDefaultView(BigImage);
_listView.CurrentChanged += new EventHandler(OnCurrentChanged);
public System.ComponentModel.ICollectionView BigImageView
{
get
{
return _listView;
}
set
{
_listView = value;
OnPropertyChanged("BigImageView");
}
}
I want to return the image to the content control when I move the listbox. I have been racking my brain and trying everyhitn but it does not work. any help would be appreciated.
There is no need to bind the selecteditem, the collectionview should take care of that.
Try this:
<ListBox ItemsSource="{Binding BigImageView}" IsSynchronizedWithCurrentItem="True" />
<ContentControl Name="Detail" Content="{Binding BigImageView, Mode=OneWay}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
<ContentControl.ContentTemplate>
1
Create a viewmodel with a list and a selected item:
public class BigImageViewModel : INotifyPropertyChanged
{
private string bigImage;
//string for path?
public ObservableCollection<string> BigImageView {get; set; } //Of course, make sure it has a value
public string SelectedBigImage
{
get { return bigImage; }
set { bigImage = values; NotifyPropertyChanged("SelectedBigImage"); }
}
}
Set this object on the DataContext of your control in the constructor:
DataContext = new BigImage(); //Make sure you initialize your list
Set the ListBox ItemsSource to your BigImage list, bind your SelectedItem to BigImageView
and use that in your content control:
<ListBox ItemsSource="{Binding BigImageView}" SelectedItem={Binding SelectedBigImage} />
ContentControl:
<ContentControl Name="Detail" Content="{Binding SelectedBigImage, Mode=OneWay}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding}"/> <!-- Nice template for showing your string BigImage -->
</DataTemplate>
<ContentControl.ContentTemplate>
</ContentControl>
2
Or screw that view model:
Set the list directly in the constructor (after the InitializeComponent() ):
myListBox.ItemsSource = ObservableCollection<string>(); //Make sure you initialize your list with whatever your object is..
Give the list a name:
And bind with an ElementName binding to your selected item:
<ContentControl Name="Detail" Content="{Binding ElementName=myListBox, Path=SelectedItem}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding}"/> <!-- Nice template for showing your string BigImage -->
</DataTemplate>
<ContentControl.ContentTemplate>
</ContentControl>

How to get TextBox inside DataTemplate in a ListBox to notify the ViewModel on value change

What I need to find is when a textbox's value is changing or the dropdown's value changes inside my datatemplate item, I need to be notified in my ViewModel.cs.
So basically as a user edits a textbox inside the listbox, the viewmodel will be notified as the values are changing.
The reason is I need to go through all my Entries and update something as items inside the listbox's datatemplate change.
Any suggetion?
I have the following in my XAML.
<ListBox x:Name="EntriesListBox"
ItemsSource="{Binding Path=Entries}"
Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox x:Name="EntriesPropertyName"
Width="215"
Margin="0,0,5,0"
SelectedItem="{Binding Path=Property, Mode=TwoWay}"
ItemsSource="{Binding Source={StaticResource DataContextProxy},Path=DataSource.EntityTypeProperties}" />
<TextBox x:Name="EntriesPropertyValue"
Width="215"
Margin="0,0,5,0"
Text="{Binding Path=Value, Mode=TwoWay, BindsDirectlyToSource=True}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The following is in my VM (ViewModel.cs)
public ObservableCollection<Entry> Entries { get; set; }
The following is in my business object (Entry.cs)
public class Entry
{
public PropertyItem Property { get; set; }
public string Value { get; set; }
}
On your binding, set the UpdateSourceTrigger... Also implement INotifyPropertyChanged
Provided that you have setup your view model class properly (by implementing INotifyPropertyChanged), following is what you may want to do:
<TextBox x:Name="EntriesPropertyValue"
Width="215"
Margin="0,0,5,0"
Text="{Binding Path=Value, Mode=TwoWay, BindsDirectlyToSource=True, UpdateSourceTrigger=PropertyChanged}" />
This seems to work. Any reason not to do it this way?
private void EntriesPropertyValue_TextChanged(object sender, TextChangedEventArgs e)
{
(sender as TextBox).GetBindingExpression(TextBox.TextProperty).UpdateSource();
this.ViewModel.UpdateFinalQuery();
}

ComboBox Binding in WPF

I am not able to set the selected value of a combobox.
this is how i am doing.
ComboBox x:Name="cmbProjectStatus" ItemsSource="{Binding ItemListCollection}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedValue="{Binding Path=ItemList.ID}"
SelectedItem="{Binding Path=ItemList}"
HorizontalAlignment="Stretch" VerticalAlignment="Center" />
I am using MVVM pattern in my project
Please Help...
but wait, your selected value is defined because you set selecteditem and selectedvaluepath ;)you don't have to set selectedvalue, andEDITItemList seted as SelectedItem exists in ItemListCollection
This should work
ComboBox x:Name="cmbProjectStatus" ItemsSource="{Binding ItemListCollection}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedItem="{Binding Path=ItemList}"
HorizontalAlignment="Stretch" VerticalAlignment="Center" />
if you want to get it worked in your case just override Equals method in your Item class like this
public class Item
{
...
public override bool Equals(object obj)
{
Item i = (Item)obj;
if (i.ID == this.ID)
return true;
return base.Equals(obj);
}
...
}

Resources