Here is part of my UI:
http://imgur.com/MtXSCnL
In the Department List, I have a list of Department objects (I am using the MVVM pattern). I access these objects through an Observable collection in the DepartmentViewModel.
I am using the Entity Framework to link with my database and I am trying to do the following:
I am binding the SelectedItem in the Department list to display information in the Department Groupbox. The problem occurs when I try to bind the department's Foreign Key (Office in this case) to the Combobox. I have an Office property of type Office in my Department viewmodel however I would like to display the OfficeName property of the Office object in the combobox and be able to modify and save changes to Department (the logic for this is already done).
How do I bind a property of type Office to display the OfficeName in the combobox?
DepartmentViewModel:
/// <summary>
/// Office
/// </summary>
private const string OfficePropertyName = "Office";
public Office Office
{
get { return _newDepartment.Office; }
set
{
_newDepartment.Office = value;
OnPropertyChanged(OfficePropertyName);
}
}
private ObservableCollection<Office> _OfficeList;
private const string OfficeListPropertyName = "OfficeList";
public ObservableCollection<Office> OfficeList
{
get
{
return _OfficeList;
}
set
{
_OfficeList = value;
OnPropertyChanged(OfficeListPropertyName);
}
}
DepartmentView
<ListBox Grid.Row="0"
ItemsSource="{Binding DepartmentList}"
DisplayMemberPath="DepartmentName"
SelectedItem="{Binding SelectedDepartment}"/>
<StackPanel Grid.Row="1" Grid.Column="2">
<TextBox Margin="10,10" Text="{Binding SelectedDepartment.DepartmentName}" />
<TextBox Margin="10,10" Text="{Binding SelectedDepartment.Supervisor}" />
<!-- List of all Office...here is where I want to show the selected office from the selected item in department list -->
<ComboBox Grid.Row="3" Grid.Column="1" Margin="10,10"
ItemsSource="{Binding OfficeList}"
DisplayMemberPath="OfficeName"
SelectedItem="{Binding Office}" />
</StackPanel>
Related
Here is my .xaml
<Picker x:Name="Title" SelectedItem="{Binding Title, Mode=TwoWay}" ItemsSource="{Binding Titles}" ItemDisplayBinding="{Binding Text}" Title="Title" />
<Entry x:Name="Name" Text="{Binding Name}" Placeholder="Name" />
Bound to a View Model .cs which looks like this
public class Person
{
public string Name { get; set; }
public string Title { get; set; }
List<SelectListItem> Titles = new(){
new SelectListItem { Text = "Mister", Value="Mr" }
new SelectListItem { Text = "Doctor", Value="Dr" }
...
}
}
Containing this data
Person person = new() { Name = "Bill Jones", Title = "Mr" };
So the picker displays the list just fine. But I have two issues.
How do I get the picker to display the correct entry when it loads, in this case, default to Mr
If I change the value in the picker, how do I get the bound ViewModel to take on that entry? (Remember I want to store the selected value, not the displayed value). I know it works with a simple string list, but that's not what I want here.
It almost feels like I need an ItemValueBinding property or something like that. (Obviously, I just made that up)
I've seen quite a lot of complicated code using INotifyPropertyChanged and doing clever bits of code in the SelectedIndexChanged event. But if I have a lot of pickers on my page that seems like a lot of code I have to write.
Is there a simpler way that I might have missed, to achieve both requirements?
If you want to set a default value of your picker, you could try like this:
Title.SelectedIndex = 0; // That means the picker chooses the first item. PickerIndex is 0-based
In your ViewModel , change Title property
public string Title {get; set;}
to this:
public SelectListItem Title {get; set;} // This will get selectedItem instead of just a Text
You could use BindingContext to bind Entry with Picker. Here i give you an example:
<Picker x:Name="Title" SelectedItem="{Binding Title, Mode=TwoWay}" ItemsSource="{Binding Titles}" ItemDisplayBinding="{Binding Text}" Title="Title"/>
<Entry x:Name="Name" BindingContext="{x:Reference Title}" Text="{Binding SelectedItem.Text}" Placeholder="Name"/>
In the above code, the x:Reference markup extension is required to reference the source object, which is the Picker named "Title". When the picker value changed, it also changed Entry's Text.
For more information, you could refer to Basic bindings and Picker.
I am able to bind SelectedItem if Selection Mode is single but if it is set to multiple then how do you bind it?
Here is what I tried for Single Selection Mode
<sync:SfDataGrid Grid.Row="1" AutoGenerateColumns="False" AllowSorting="True"
AllowGroupExpandCollapse="True" AutoExpandGroups="True"
SelectionMode="Multiple" ColumnSizer="Star"
ItemsSource="{Binding LstItems}"
SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}"
>
<sync:SfDataGrid.Columns>
<sync:GridTextColumn HeaderText="Name" MappingName="Name" />
<sync:GridTextColumn HeaderText="MRP" MappingName="MRP"/>
<sync:GridTextColumn HeaderText="Category" MappingName="Category" Width="0"/>
</sync:SfDataGrid.Columns>
<sync:SfDataGrid.GroupColumnDescriptions>
<sync:GroupColumnDescription ColumnName="Category"/>
</sync:SfDataGrid.GroupColumnDescriptions>
</sync:SfDataGrid>
In the above xaml, selection mode is set to multiple but I am unable to get the SelectedItems in xaml as mentioned here
https://help.syncfusion.com/xamarin/sfdatagrid/selection
In SfDataGrid, it is not possible to bind the SfDataGrid.SelectedItems property to the view model as like SelectedItem property since we can only get the selected items in SfDataGrid. Hence, you will not be able to bind the values in XAML for SelectedItems property.
However, you can achieve your requirement by writing behavior for SfDataGrid which will not affect the MVVM pattern. Please refer the below code snippet.
<sfGrid:SfDataGrid x:Name="dataGrid"
AutoGenerateColumns="True"
ItemsSource="{Binding OrdersInfo}"
SelectionMode="Multiple">
<b:Interaction.Behaviors>
<b:BehaviorCollection>
<b:EventToCommand Command="{Binding SelectionCommand}"
CommandParameter="{x:Reference Name=dataGrid}"
EventName="SelectionChanged" />
</b:BehaviorCollection>
</b:Interaction.Behaviors>
</sfGrid:SfDataGrid>
// In ViewModel.cs
public ViewModel()
{
selectionCommand = new Command<SfDataGrid>(onSelectionChanged);
selectedItems = new ObservableCollection<object>();
}
private Command<SfDataGrid> selectionCommand;
public Command<SfDataGrid> SelectionCommand
{
get { return selectionCommand; }
set { selectionCommand = value; }
}
private ObservableCollection<object> selectedItems;
public ObservableCollection<object> SelectedItems
{
get { return selectedItems; }
set { selectedItems = value; }
}
private void onSelectionChanged(SfDataGrid obj)
{
//you can get the selected items in the datagrid
selectedItems = obj.SelectedItems;
}
Also, we have prepared a sample for your reference and you can download the same from the below link.
Sample link: http://www.syncfusion.com/downloads/support/directtrac/168321/ze/DataGridDemo352928928
Regards,
Divakar.
Here is the XAML code:
<maps:Map x:Name="NearbyMap"
Center="{Binding MapCenter, Mode=TwoWay}"
ZoomLevel="{Binding ZoomLevel, Mode=TwoWay}"
>
<maptk:MapExtensions.Children>
<maptk:MapItemsControl Name="StoresMapItemsControl" ItemsSource="{Binding Treks}">
<maptk:MapItemsControl.ItemTemplate>
<DataTemplate>
<maptk:Pushpin x:Name="RouteDirectionsPushPin" GeoCoordinate="{Binding Location}" Visibility="Visible" Content="test"/>
</DataTemplate>
</maptk:MapItemsControl.ItemTemplate>
</maptk:MapItemsControl>
<maptk:UserLocationMarker x:Name="UserLocationMarker" Visibility="Visible" GeoCoordinate="{Binding MyLocation}"/>
</maptk:MapExtensions.Children>
</maps:Map>
xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"
xmlns:maptk="clr-namespace:Microsoft.Phone.Maps.Toolkit;assembly=Microsoft.Phone.Controls.Toolkit"
PushPinModel has an attribute Location which is a GeoCoordinate. Treks is an ObservableCollection<PushPinModel>. I run this code and only the UserLocationMarker is displayed, which is my current location.
I finally make it work by using dependency property. I added a new class:
public static class MapPushPinDependency
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.RegisterAttached(
"ItemsSource", typeof(IEnumerable), typeof(MapPushPinDependency),
new PropertyMetadata(OnPushPinPropertyChanged));
private static void OnPushPinPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
UIElement uie = (UIElement)d;
var pushpin = MapExtensions.GetChildren((Map)uie).OfType<MapItemsControl>().FirstOrDefault();
pushpin.ItemsSource = (IEnumerable)e.NewValue;
}
#region Getters and Setters
public static IEnumerable GetItemsSource(DependencyObject obj)
{
return (IEnumerable)obj.GetValue(ItemsSourceProperty);
}
public static void SetItemsSource(DependencyObject obj, IEnumerable value)
{
obj.SetValue(ItemsSourceProperty, value);
}
#endregion
}
And in the .xaml file I have added
xmlns:dp="clr-namespace:Treks.App.Util.DependencyProperties"
and now the .xaml file looks like this:
<maps:Map x:Name="NearbyMap"
Center="{Binding MapCenter, Mode=TwoWay}"
ZoomLevel="{Binding ZoomLevel, Mode=TwoWay}"
dp:MapPushPinDependency.ItemsSource="{Binding Path=Treks}"
>
<maptk:MapExtensions.Children>
<maptk:MapItemsControl Name="StoresMapItemsControl">
<maptk:MapItemsControl.ItemTemplate>
<DataTemplate>
<maptk:Pushpin x:Name="PushPins" GeoCoordinate="{Binding Location}" Visibility="Visible" Content="test"/>
</DataTemplate>
</maptk:MapItemsControl.ItemTemplate>
</maptk:MapItemsControl>
<maptk:UserLocationMarker x:Name="UserLocationMarker" Visibility="Visible" GeoCoordinate="{Binding MyLocation}"/>
</maptk:MapExtensions.Children>
</maps:Map>
Now all the pushpins are correctly rendered.
The MapItemsControl is currently not yet MVVM bindable ( what I am aware off ).
So best way is to set it's ItemsSource in the code behind of your view.
You can still use the collection defined in your ViewModel though!
Options are:
through mvvm messaging pass along the collection from the viewmodel to the code behind of the view
use the datacontext of the view to access the collection, something like this: this.StoresMapItemsControl.ItemsSource = ServiceLocator.Current.GetInstance<MainViewModel>().Locations;
I'm trying to bind a View to my ContentControl. Currently, it just shows me the type (eg NameSpace.ViewModel.MainWindowViewModel)
Although I will point out, I'm not sure if I'm approaching this correctly.
My simple set up is I have a View (UserControl) which is empty other than a single control (which has been placed just for the visual).
My MainWindow.xaml
<Window x:Class="DelegateGoodExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:DelegateGoodExample.ViewModel"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<viewModel:MainWindowViewModel x:Key="Vm" />
</Window.Resources>
<Grid>
<ContentControl Height="147" Margin="53,132,60,0"
VerticalAlignment="Top"
Content="{StaticResource Vm}" />
</Grid>
</Window>
(There is nothing in the code behind).
My MainWindowViewModel.cs
namespace DelegateGoodExample.ViewModel
{
public class MainWindowViewModel
{
private object _currentView;
public object CurrentView
{
get { return new View.QuickView(); }
set { _currentView = value; }
}
}
}
So, my question is,
Do I have to set a datacontext in this instance (and even if I do add it the results persist)?
What have I done wrong?
You are putting a viewmodel inside the ContentControl, not a view. Since your viewmodel class is not a UIElement and there is no DataTemplate to determine how it should be rendered, what gets displayed is simply its .ToString() representation.
An immediate fix would be:
<ContentControl Height="147" Margin="53,132,60,0"
VerticalAlignment="Top"
Content="{Binding Source={StaticResource Vm}, Path=View}" />
However, instead of doing things this way you should be putting your view inside the Grid directly, and the viewmodel should not have any knowledge of the view.
i have my View Page with a GridView control. Items in the Grid are edited using a popup Childwindows with the following xaml:
<toolkit:DataForm.EditTemplate>
<DataTemplate>
<StackPanel>
<toolkit:DataField Label="Avisar a: ">
<ComboBox ItemsSource="{Binding Path=Sucursales}"/>
</toolkit:DataField>
<toolkit:DataField Label="Mensaje:">
<TextBox Text="{Binding mensaje, Mode=TwoWay}"/>
</toolkit:DataField>
<toolkit:DataField Label="Estado: ">
<ComboBox ItemsSource="{Binding Path=EstadosMensaje}"/>
</toolkit:DataField>
</StackPanel>
</DataTemplate>
</toolkit:DataForm.EditTemplate>
</toolkit:DataForm>
DataContext to this popup is injected view constructor from the parent view as follow:
AlertaForm frm = new AlertaForm(DataContext as AlertasViewModel);
frm.Show();
//ChildWindows constructor
public AlertaForm(AlertasViewModel viewModel){
InitializeComponent();
DataContext = viewModel;
}
As you can see, ChildWindows and parent view share the same ViewModel.
The problem is that ComboBox controls dont get populated. TextBox field are binded correctly,they display values from DataContext property, that is confusing because that prove that the DataForm recognize the ViewModel passed to the ChildWindows AlertaForm.
Obviously i'm missing something here but cannot figure out what is.
Thanks
I end up throwing away the User control with the DataForm together
sticking in ChildWindows with common controls. It seems that DataForm is not sweet to
complex scenarios