MVVM Property for datagrid itemssource - wpf

I have a datagrid whose itemsSource is bound to a multiconverter which uses a converter.
<toolkit:DataGrid AutoGenerateColumns="False">
<toolkit:DataGrid.ItemsSource>
<MultiBinding Converter="{StaticResource ProfileConverter}">
<Binding ElementName="ComboBoxProfiles" Path="SelectedValue" />
<Binding ElementName="DatePickerTargetDate" Path="SelectedDate" />
</MultiBinding>
</toolkit:DataGrid.ItemsSource>
This is good because the itemsSource of the grid is updated whenever the combobox or datepicker changes value.
The problem I now have is that in my ViewModel I want to be able to access the ItemSource of my datagrid and either remove items for the list or add new ones.
How do I get access to the itemssource when I have it set up like this?
Many thanks.

How about having three properties in the ViewModel:
public DateTime? SelectedDate
{
get{return _selectedDate;}
set
{
_selectedDate = value;
UpdateItemsSource();
OnPropertyChanged("SelectedDate");
}
}
public object SelectedComboBoxValue
{
get{return _selectedComboBoxValue;}
set
{
_selectedComboBoxValue= value;
UpdateItemsSource();
OnPropertyChanged("SelectedComboBoxValue");
}
}
private void UpdateItemsSource()
{
_itemsSource = //Some fancy expression based on the two fields.
OnPropertyChanged("ItemsSource");
}
public IEnumerable ItemsSource
{
get{return _itemsSource;}
}
Then bind the datepicker, combobox and datagrid to the respective values.
Hope this helps.

Related

WPF: Multibinding not updating with OnPropertyChanged?

I have a converter that takes in a bool and will return A or B depending on if it was true or false. The converter picks the right value depending on what the bool is, but only at start, if i change the bool at runtime the converter does not update.
Basically, i have a User Control that has a button in it, this button toggles the "IsOpen" property, this works. But i have a multibinder who binds IsOpen to Image (of button) which will toggle the image depending on IsOpen. But it is not updating, only keeps the value at start. (IsOpen does toggle on click, that's not the problem)
My User Control where i do the multibinding:
<v:IconButton ColorPalette="{StaticResource MilkySolid}" ColorPaletteFore="{StaticResource BlackToBrightPalette}" IconMargin="0" Content="" VerticalAlignment="Top" Margin="0" HorizontalAlignment="Left" FontSize="1" Height="26" IconWidth="26" Click="IconButton_Click">
<v:IconButton.Image>
<MultiBinding Converter="{StaticResource AorBConverter}">
<Binding Path="IsOpen"/>
<Binding Source="{StaticResource collapseBTN}"/>
<Binding Source="{StaticResource expandBTN}"/>
</MultiBinding>
</v:IconButton.Image>
</v:IconButton>
CodeBehind (this part works)
private void IconButton_Click(object sender, RoutedEventArgs e)
{
IsOpen = !IsOpen;
}
public bool IsOpen
{
get { return (bool)GetValue(IsOpenProperty); }
set { SetValue(IsOpenProperty, value); }
}
public static readonly DependencyProperty IsOpenProperty =
DependencyProperty.Register("IsOpen", typeof(bool),
typeof(ParamNodeV), new PropertyMetadata(false));
Viewmodel for the user control (this also works)
public bool IsOpen
{
get { return isOpen; }
set
{
isOpen = value;
OnPropertyChanged(nameof(IsOpen));
}
}
So, like i said, the converter chooses the right image depedning on the bool value. But it does not update if i update the bool value at runtime.
And if you will ask me why im not just using a trigger: I'm trying to change the image on a CustomControl (IconButton) from my UserControl (ParamNodeV), and i don't know how to access the properties of IconButton from ParamNodeV, without completely overriding the style/template. So either if someone helps me with my converter or helps me on how to navigate to the Image property of IconButton from UserControl without having to override the style/template
The expression
<Binding Path="IsOpen"/>
takes the current DataContext as source object.
In the code behind you are apparently changing the IsOpen property of the UserControl - which should be a different object.
The Binding should therefore use that property as source, i.e. use the UserControl as source object:
<Binding Path="IsOpen" RelativeSource="{RelativeSource AncestorType=UserControl}"/>

WPF binding - DataGrid.Items.Count

in my View, there are a DataGrid and a TextBox, which is bound to the DataGrid's Items.Count property:
<DataGrid x:Name="dataGrid" ItemsSource="{Binding dataTable}"/>
<TextBox Text="{Binding Items.Count,ElementName=dataGrid,Mode=OneWay,StringFormat={}{0:#}}"/>
The ViewModel has a property (e.g. ItemsCount) which I'd like to be bound to the Items.Count property of the DataGrid, but have no idea, how to achieve this.
class ViewModel : INotifyPropertyChanged
{
public DataTable dataTable {get;set;}
public int ItemsCount {get;set;}
}
Maybe I could also use the Rows.Count property of the DataTable the DataGrid is bound to, but how would i bind or link the two properties in the ViewModel?
So I basically want the ItemsCount property to be synchronized with the dataTable.Rows.Count property.
A common way to achieve your requirements are to declare properties to data bind to the UI controls:
<DataGrid x:Name="dataGrid" ItemsSource="{Binding Items}" />
<TextBox Text="{Binding ItemsCount}" />
...
// You need to implement the INotifyPropertyChanged interface properly here
private ObservableCollection<YourDataType> items = new ObservableCollection<YourDataType>();
public ObservableCollection<YourDataType> Items
{
get { return items; }
set { items = value; NotifyPropertyChanged("Items"); NotifyPropertyChanged("ItemCount"); }
}
public string ItemCount
{
get { Items.Count.ToString("{0:#}"); }
}
UPDATE >>>
As #Sivasubramanian has added his own requirement to your question, in case you need to update the item count specifically by adding to your collection, you can manually call the NotifyPropertyChanged method:
Items.Add(new YourDataType());
NotifyPropertyChanged("ItemCount");

selectedvalue of combobox in datagrid not getting set - silverlight mvvm model

Below is the XAML snippet for my combo-box in a datagrid.
<data:DataGridTemplateColumn Header="Entry Mode">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=EntryModeCombo,Mode=TwoWay}" DisplayMemberPath="Name" SelectedValuePath="Id" SelectedValue="{Binding Path=selectedEntryMode,Mode=TwoWay}" ></ComboBox>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
Entrymode is an entity in the system and the Id and Name properties of this entity are used to set the DisplayMemberPath and SelectedValuePath of the combo.
public class A
{
private ObservableCollection<EntryMode> _EntryModeCombo;
public ObservableCollection<EntryMode> EntryModeCombo
{
get { return _EntryModeCombo; }
set
{
_EntryModeCombo = value;
RaisePropertyChanged("EntryModeCombo");
}
}
private string _selectedEntryMode;
public string selectedEntryMode
{
get { return _selectedEntryMode; }
set
{
_selectedEntryMode = value;
RaisePropertyChanged("selectedEntryMode");
}
}
}
In my viewModel, I am making an observable collection of the class A, and using that to bind a grid. All works well in the ADD mode, but in the edit mode, when I try to set the selected value of the combobox in the grid, it does not work. The population of the combo-box happens, but it remains unselected. Not sure why the selectedEntryMode property is getting set, but not affecting the combo selection in the grid.
Any suggestions will be appreciated.Thanks.
SelectedValue can only be used for getting value. not setting. use SelectedItem insted

MultiBinding to the Title Property of a wpf user control?

I need to format the Title property of my user control. For this I am trying to make use of MultiBinding with StringFormat.
The Xaml I use is :
<Control x:Name="myControlName">
<Control.Title>
<MultiBinding StringFormat="You have {0} of {1} items. ">
<Binding Path="MyNumber"></Binding>
<Binding Path="TotalNumber"></Binding>
</MultiBinding>
</Control.Title>
</Control>
For some reason this does not seem to work.
Am I missing something here? Thanks!
I would recommend binding the Title property to a property on a ViewModel if using MVVM or just a property on the code behind if not.
<Control x:Name="myControlName" Title={Binding Path=MyTitle}>
</Control>
public class MyView
{
public int MyNumber { get; set; }
public int TotalNumber { get; set; }
public string MyTitle
{
get { return string.Format("You have {0} of {1} items. ", MyNumber, TotalNumber); }
}
}

CheckedItems property for custom CheckBoxList control in Silverlight

I need to implement CheckBoxList control with ItemsSource and CheckedItems properties. Items from ItemsSource should be displayed as checked checkboxes if CheckedItems contains these values or unchecked otherwise. Also I need two-way databinding support for CheckedItems property (value of this property should be updated when user clicks on checkboxes).
Here some code which probably can help to understand my problem
XAML:
<UserControl x:Class="Namespace.Controls.CheckBoxList" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox x:Name="LayoutRoot">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
Code behind:
public partial class CheckBoxList : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(CheckBoxList), null);
public static readonly DependencyProperty CheckedItemsProperty = DependencyProperty.Register("CheckedItems", typeof(IEnumerable), typeof(CheckBoxList), null);
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public IEnumerable CheckedItems
{
get { return (IEnumerable)GetValue(CheckedItemsProperty); }
set { SetValue(CheckedItemsProperty, value); }
}
public CheckBoxList()
{
InitializeComponent();
LayoutRoot.SetBinding(ItemsControl.ItemsSourceProperty, new Binding("ItemsSource") { Source = this });
}
}
I think that I need to bind ListBox to UserControl with custom converter, which will return collection of items with additional IsChecked property, but it works only in case of one-way data binding.
Looks like I need two-way binding to two properties at one time, but I don't know how to implement it and will appreciate any help with this issue.
Thanks in advance.
First of all you should consider deriving from ListBox rather than UserControl. The ListBox already does most of what you want.
Secondly consider one way binding to an IList. You can then add and remove entires to that IList as the respective items are selected.
Rather than try to bind a CheckBox control in an Item Template you make a copy of the ListBox styles, place them in Generic.xaml as the style of your new control. Then modify the unselected and selected visual states using a checked and unchecked check box as part of the visual appearance.
Now you can attach to the SelectionChanged event and use the Event args AddedItems list to add to the bound IList and the RemovedItems list to remove items from the bound list.
You would need to clear and re-add the set of items to the list box SelectedItems list when either your CheckedItems is assigned or the ItemsSource is changed.
There are probably a number gotchas that you will need to work round but this seems like a more direct path to your goal than starting from scratch with a UserControl base.
Add an observable collection for your list box datasource to your datacontext:
private ObservableCollection<MyItem> _myItems;
public ObservableCollection<MyItem> MyItems
{
get { return _searchByFields; }
set
{
_myItems = value;
}
}
Add a class to hold the data about your checkboxes:
public class MyItem
{
public bool Checked {get; set; }
public string MyItemValue { set ; set; }
}
Then in your data template bind listbox to the collection and your data template checkboxes to the respective MyItem properties:
<UserControl x:Class="Namespace.Controls.CheckBoxList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox x:Name="LayoutRoot"
DataContext="[Dataconext here]"
ItemsSource={Binding MyItems}>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Checked, Mode=TwoWay}"
Content="{Binding MyItemValue}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
Don't forget to set the DataContext of the binding to the appropriate class (you might be doing this in the XAML or the code behind perhaps)

Resources