I created a my own user control wrappping a GridControl and defined some columns, so I can reuse this control in multiple places. I created a dependency property called AttachmentList in my user control to hold a list of strings I want to display in the grid.
<dxg:GridControl AutoGenerateColumns="None" EnableSmartColumnsGeneration="True"
ItemsSource="{Binding Path=AttachmentList, Mode=TwoWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged}"/>
I my parent window, I use
<vm:FileListGridControl AllowDrop="True"
AttachmentList="{Binding Path=Email.FileList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<dxmvvm:Interaction.Behaviors>
<vm:GridDragDropBehavior/>
</dxmvvm:Interaction.Behaviors>
</vm:FileListGridControl>
Email.FileList is defined as ObservableCollection in my ViewModel. GridDragDropBehavior will call Email.FileList.Add() to add strings to Email.FileList. Problem is I can see strings have been added to FileList, but not shown in the GridControl.
I though use ObserableCollection and twoway binding should update the UI. What did I do wrong?
Edit Here are the defintions
public static readonly DependencyProperty AttachmentListProperty = DependencyProperty.Register("AttachmentList", typeof(IList<FileWrapper>), typeof(FileListGridControl));
public IList<FileWrapper> AttachmentList
{
get { return (IList<FileWrapper>)GetValue(AttachmentListProperty); }
set { SetValue(AttachmentListProperty, value); }
}
In My Email class, I defined
ObservableCollection<FileWrapper> _FileList = new ObservableCollection<FileWrapper>();
public ObservableCollection<FileWrapper> FileList { get { return _FileList; } set { _FileList = value; } }
If I remove my control and add the GridControl directly in the Parent window, everything works as expected.
Related
I have a user control (WaypointInfoControl) that I wrote that has a dependency property named TheGraphic as shown here:
public Graphic TheGraphic
{
get { return (Graphic)GetValue(TheGraphicProperty); }
set { SetValue(TheGraphicProperty, value); }
}
public static readonly DependencyProperty TheGraphicProperty =
DependencyProperty.Register("TheGraphic", typeof(Graphic), typeof(WaypointInfoControl), new PropertyMetadata(default(Graphic)));
I have a viewmodel that has a Waypoints property defined like this:
private ObservableCollection<Graphic>_Waypoints = new GraphicCollection();
public ObservableCollection<Graphic> Waypoints
{
get { return _Waypoints; }
set { RaiseAndSetIfChanged(ref _Waypoints, value); }
}
In my xaml, I have a ListView that I want to populate with Waypoints:
<ListView ItemsSource="{Binding Waypoints}" >
<ListView.ItemTemplate >
<DataTemplate >
<controld:WaypointInfoControl TheGraphic="????" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
How do I bind TheGraphic to the individual item in the ListView that it represents?
Your ItemsSource is bound to a collection of Graphic objects which means that the DataContext for each item in your ListView will be a single Graphic object. Since the DependencyProperty that you are looking to bind to is looking for the Graphic object you will just want to bind to the entire DataContext, you achieve this by using the binding markup extension without specifying a path (this just causes the binding to pull in the entire DataContext which in your case is the Graphic object that you are looking for).
So this should work:
<ListView ItemsSource="{Binding Waypoints}" >
<ListView.ItemTemplate >
<DataTemplate >
<controld:WaypointInfoControl TheGraphic="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Have a WPFDatagrid binded to combobox using Datagridtemplatecolumn. Finding difficult to get the selectedItem of the combobox binding. Have found similar examples around but that's not resolving my problem.
Please find the code snippet of my XAML and the data structure below:
public class X
{
public X ()
{
abc = new ObservableCollection<P>();
}
public ObservableCollection<P> Y
{
get { return abc; }
set { abc = value; PropertyChanged("Y"); }
}
}
public class P
{
private string id;
private string name;
public string ID
{
get
{
return id;
}
set
{
id = value;
InvokePropertyChanged("ID");
}
}
public string Name
{
get
{
return name;
}
set
{
name = value;
InvokePropertyChanged("Name");
}
}
}
I have a datastructure defined above that implements the INotifyPropertychanged interface.
<controls:DataGrid Name="datagrid" AutoGenerateColumns="False" ItemsSource="{Binding XList}" Grid.Row="0"
SelectedItem="{Binding SelectedX, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<controls:DataGrid.Columns>
<controls:DataGridTemplateColumn Header="Yl">
<controls:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Y}"
IsSynchronizedWithCurrentItem="False" DisplayMemberPath="Name"
SelectedValue="{Binding Path=SelectedY, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnTargetUpdated=True}"
SelectedValuePath="SelectedY"
SelectedItem="{Binding SelectedY, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</controls:DataGridTemplateColumn.CellTemplate>
</controls:DataGridTemplateColumn>
</controls:DataGrid.Columns>
</controls:DataGrid>
Now, in view model, have a observablecollection of List of X i.e., XList and that is binded to the datagrid in the XAML. and have Y within each row of the datagrid binded to the Combobox. Have a property as SelectedY, binded to the SelectedItem of the combobox.
Have also a property as SelectedX binded to the selectedItem of the datagrid, which works fine.
Issue is not able to get the Selected Item binding of the Combobox. Not able to set the selected item for the combobox when the selection has changed.
Can anybody help me out to set the selecteditem binding of the combo box?
Where is set your datacontext ?
You can do something like that :
<controls:UserControl x:Name=MainControl>
<controls:UserControl.DataContext>
<classpath:X/>
</controls:UserControl.DataContext>
<controls:DataGrid ItemsSource={Binding YourItemsContainer}>
<controls:DataGrid.Columns>
<controls:DataGridComboBoxColumn ItemsSource={Binding ElementName=MainControl,Path=DataContext.Y}
SelectedItem={Binding ElementName=MainControl,Path=DataContext.SelectedY}
DisplayMemberPath=Name />
</controls:DataGrid.Columns>
</controls:DataGrid>
</controls:UserControl>
The idea is to set a name to the root element connected to your datacontext, then you can access to it's datacontext property easily by the path. When you are inside of a template, the datacontext is the ItemsSource objects.
Hope it will help you a little !
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
I am databinding a view to a viewmodel and am having trouble initializing a combobox to a default value. A simplification of the class I'm using in the binding is
public class LanguageDetails
{
public string Code { get; set; }
public string Name { get; set; }
public string EnglishName { get; set; }
public string DisplayName
{
get
{
if (this.Name == this.EnglishName)
{
return this.Name;
}
return String.Format("{0} ({1})", this.Name, this.EnglishName);
}
}
}
The combobox is declared in the view's XAML as
<ComboBox x:Name="LanguageSelector" Grid.Row="0" Grid.Column="1"
SelectedItem="{Binding SelectedLanguage,Mode=TwoWay}"
ItemsSource="{Binding AvailableLanguages}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
and the viewmodel contains this code
private List<LanguageDetails> _availableLanguages;
private LanguageDetails _selectedLanguage;
public LoginViewModel()
{
_availableLanguages = LanguageManager.GetLanguageDetailsForSet(BaseApp.AppLanguageSetID);
_selectedLanguage = _availableLanguages.SingleOrDefault(l => l.Code == "en");
}
public LanguageDetails SelectedLanguage
{
get { return _selectedLanguage; }
set
{
_selectedLanguage = value;
OnPropertyChanged("SelectedLanguage");
}
}
public List<LanguageDetails> AvailableLanguages
{
get { return _availableLanguages; }
set
{
_availableLanguages = value;
OnPropertyChanged("AvailableLanguages");
}
}
At the end of the constructor both _availableLanguages and _selectedLanguage variables are set as expected, the combobox's pulldown list contains all items in _availableLanguages but the selected value is not displayed in the combobox. Selecting an item from the pulldown correctly displays it and sets the SelectedLanguage property in the viewmodel. A breakpoint in the setter reveals that _selectedLanguage still contains what it was initialized to until it is overwritten with value.
I suspect that there is some little thing I'm missing, but after trying various things and much googling I'm still stumped. I could achieve the desired result in other ways but really want to get a handle on the proper use of databinding.
You need to change the order of you bindings in XAML so that your ItemsSource binds before the SelectedItem.
<ComboBox x:Name="LanguageSelector" Width="100"
ItemsSource="{Binding AvailableLanguages}"
SelectedItem="{Binding SelectedLanguage,Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
If you set a breakpoint on the 'get' of both the SeletedLanguage and AvailibleLanguage, you will notice that the SelectedLanguage gets hit before your AvailibleLanguage. Since that's happening, it's unable to set the SelectedLanguage because the ItemsSource is not yet populated. Changing the order of the bindings in your XAML will make the AvailibleLanguages get hit first, then the SelectedLanguage. This should solve your problem.
1) When you assign the SelectedLanguage, use the public property SelectedLanguage instead of the private _selectedLanguage, so that the setter gets executed,
2) You need to move the assignment of the selectedlanguage to the moment that the view has been loaded. You can do it by implementing the Loaded event handler on the View. If you want to be "mvvm compliant" then you should use a Blend behavior that will map UI loaded event to a viewmodel command implementation in which you would set the selected language.
I have a WPF user control with a list box. I want to pass the selected item in the list box to the calling control through binding. How can I achieve this?
You can expose a new property for SelectedItem on your user control and bind it to the child control ListBox.
Code for your user control (I inherited from Control though):
public class CustomListControl : Control
{
static CustomListControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomListControl), new FrameworkPropertyMetadata(typeof(CustomListControl)));
SelectedItemProperty = ListBox.SelectedItemProperty.AddOwner(typeof(CustomListControl));
}
public static readonly DependencyProperty SelectedItemProperty;
public Object SelectedItem
{
get { return this.GetValue(SelectedItemProperty); }
set { this.SetValue(SelectedItemProperty, value); }
}
}
And add the binding from the inner ListBox to your UserControl in the Generic.xaml markup:
<ListBox
SelectedItem="{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type local:CustomListControl},Mode=FindAncestor},Path=SelectedItem, Mode=TwoWay}"
</ListBox>