Silverlight Data Binding in Nested Controls - silverlight-4.0

Hi guys I am working with SL4 and MVVM application actually i am stuck some where i might be doing some thing wrong thats why need your help, here is my scenario
//suodo code
public class EmployeeModel
{
//code
Public List<Shifts> Employeeshifts{get;set;}
}
public class ShiftModel
{
//code
}
Viewmodel for main page
public class MainVM
{
MainVM()
{
EmployeeList = DateFromSomeService;
}
Public List<Employees> EmployeeList{get;set}
Public DelegateCommand ClickBindingCommand{get;set;}
}
MainPage.xaml
<ItemsControl ItemSource={Binding EmployeeList}>
<ItemTemplate>
<DataTemplate>
<controls:EmployeeControl/>
</DataTemplate>
</ItemTemplate>
</ItemsControl>
Employeecontro.xaml
<ItemsControl ItemSource={Binding EmployeeShifts}>
<ItemTemplate>
<DataTemplate>
<controls:ShiftControl Click={Binding ClickBindingCommand}/>//here is problem this command is in mainviewmodel
</DataTemplate>
</ItemTemplate>
</ItemsControl>
MainPage.cs
this.DataContext = new MainVM();
ClickBindingCommand is defined in main VM but it is bound within shift control and shiftcontrol's data context is shift class which is my model class. If I declare this command in my shift model class than it works, means if I click on shift control this property is called but I dont want this because I want it in my main view model, where am I wrong?
Should I declare it in my shift model class but in this way i will bind directly my model to my view?

Use a DataContextProxy or a RelativeSource Binding. This will allow your Command to bind/fire on your MainViewModel.
Another alternative is to use the Caliburn Micro framework. You can then attach an action to your button in the child and click events will bubble up to the parent.

This "toolkit" offers an implementation of FindAncestor in silverlight. Try this:
http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/

I ran into this same issue and what fixed it for me was to name my UserControl then reference that name in the binding.
Here is the syntax:
{Binding ElementName=SomeTextBox, Path=Text}
Bind to the “Text” property of the element XAML
element with name=”SomeTextBox” or x:Name=”SomeTextBox”.
So here is my user control:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SupportReports.Workflow.Portfolio.PortfolioManager"
mc:Ignorable="d"
Name="PortfolioManagerControl"
>
And here is the nested dataTemplate that binds to my command in my main view model
<cmd:EventToCommand Command="{Binding ElementName=PortfolioManagerControl, Path=DataContext.PortfolioManagerProjectSelectedCommand}" CommandParameter="{Binding Text, ElementName=ProjectName}" />

Related

Add Complex argument for viewmodel constructor in XAML

There is bindable Item source of Flexlayout
<FlexLayout x:Name="playerscollection" Wrap="Wrap" BindableLayout.ItemsSource="{Binding Players}" />
Items in the viewmodel are defined as
public ObservableCollection<PlayerModel> Players { get; set; }
FlexLayout datatemplate is a content view
I need to assign a specific viewmodel "PlayerViewModel" as the content view BindingContext
public PlayerViewModel(bool showPicker = true, PlayerModel player = null){}
So in FlexLayout,
<FlexLayout x:Name="playerscollection" Wrap="Wrap" BindableLayout.ItemsSource="{Binding Players}">
<views:PlayerView >
<views:PlayerView.BindingContext>
<viewModels:PlayerViewModel>
<x:Arguments>
<x:Boolean>False</x:Boolean>
<models:PlayerModel/>
</x:Arguments>
</viewModels:PlayerViewModel>
</views:PlayerView.BindingContext>
</views:PlayerView>
</FlexLayout>
But the error says "Type 'PlayerViewModel' is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter"
I've created a basic demo to test the code and reproduce the error. The error doesn't affect the project build, it's just an intellisense error of the IDE. Please ignore the error and deploy the code, it'll work fine.

Dynamically change DataTemplate for a ListView at Runtime

I have 2 DataTemplates for displaying the contents of ClassA or ClassB inside a single ListView; which template to select will be based on a RadioButton selection by the user.
Is it possible to change the ItemTemplate of a ListView (in XAML) based on user input dynamically at runtime?
An example snippet of code:
XAML Page:
<Page...>
<Page.Resources>
<DataTemplate x:Key="ClassAListViewItemTemplate" x:DataType="vm:ClassA" ... />
<DataTemplate x:Key="ClassBListViewItemTemplate" x:DataType="vm:ClassB" ... />
</Page.Resources>
<RelativePanel>
<RadioButton Content="ClassA" ... />
<RadioButton Content="ClassB" ... />
<ListView DataContext="{Binding Path=MainViewModel}"
ItemsSource="{Binding ListOfClassAOrB, Mode=TwoWay}"
ItemTemplate="{StaticResource ClassAListViewItemTemplate}"/>
</RelativePanel>
</Page>
I have stripped the code down somewhat to the essentials, but I would like to be able to change the following at runtime:
ItemTemplate="{StaticResource ClassAListViewItemTemplate}"
I have seen solutions for Classic WPF applications that use Style.Triggers, but these aren't applicable for UWP
Marco Minerva's blog on Adaptive Triggers, RelativePanel and DataTemplate in the Universal Windows Platform talks of using UserControls within DataTemplates to modify the visual state using Adaptive Triggers, but this doesn't take into account switching out of templates based on user input
The closest answer I have found to my problem is another blog he wrote "Dynamically choose DataTemplate in WinRT" where there is an element of code-behind involved - but it only appears to be an if statement - but its the cleanest solution I have come across thus far, and what I'd like to replicate in XAML
Thanks
you need to use overwrite SelectTemplateCore of Data template. Change your view model like this.
Below code will helps you.
public class SampleViewModel : DataTemplateSelector
{
public DataTemplate ClassAListViewItemTemplate{ get; set; }
public DataTemplate ClassBListViewItemTemplate{ get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var itemsData = item as SampleClass; // add your Data class
if (itemsData.IsAddButton == false) // define any property to select the datatemplate
{
return ClassAListViewItemTemplate;
}
else
{
return ClassBListViewItemTemplate;
}
}
}
Add your two datatemplates to one key, and give the key to ItemTemplateSelector property in gridview.
<viewModels:SampleViewModel x:Key="FeedbackTempateSelector"
ClassAListViewItemTemplate="{StaticResource ClassAListViewItemTemplate}"
ClassBListViewItemTemplate="{StaticResource ClassBListViewItemTemplate}">
</viewModels:SampleViewModel>

Bind tab to observablecollection in model in xaml

I have a question concerning data binding with tabs.
I have the following xaml code:
<Window x:Class="SuperAtomsController.GUI.windowAnalog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="windowAnalog" Height="900" Width="1400"
DataContext="{Binding RelativeSource={RelativeSource self}}">
<Grid>
<TabControl Height="459" HorizontalAlignment="Left" Margin="188,278,0,0" Name="tabControl1" ItemsSource="{Binding Path=model.sequences}" VerticalAlignment="Top" Width="883">
</TabControl>
</Grid>
</Window>
And the code behind:
public partial class windowAnalog : Window
{
public Data model;
public windowAnalog(Data model)
{
this.model = model;
InitializeComponent();
}
}
But with this nothing appears in the tabcontrol (model.sequences is of the type ObservableCollection<>). If remove the itemssource in xaml and add the following in the c# code tabControl1.ItemsSource = model.sequences; after the InitializeComponent(); it works fine. What am I missing?
Clearly your binding isn't resolving, check your debug output window for helpful diagnostic messages.
I can't recall but I think model may need to be a property instead of a field for WPF property path to work. Otherwise maybe it was a problem with the DataContext. You coudl try doing this.DataContext = this to your constructor before InitializeComponent() instead of your DataContext xaml.

Metro Xaml binding to DataContext.Object.Property not working

I am setting the datacontext of my xaml page to a viewmodel passed in to the construrctor. My viewmodel has an object called Item, which has a property called Category.
public DataEntry(DEViewModel vm)
{
InitializeComponent();
this.vm = vm;
this.DataContext = this.vm;
}
I am trying to bind to the ViewModel.Item.Category property like so:
<TextBox Name="txtCategory" Text="{Binding Path=Item.Category, Mode=TwoWay}" />
This does not work. If I set the datacontext to vm.Item, and bind to Category it works.
Any ideas on how to bind to a property that is hanging off of an object on the viewmodel?
Thanks, Terrence
Do it like this,
<TextBox Name="txtCategory"
Text="{Binding Category, Mode=TwoWay}"
DataContext="{Binding Item}" />
The reason it was not working is because it will only look at property notifications for the DataContext, so just set the local DataContext for the control to Item and the control will handle property notifications for Item.
Thanks,
Alex.

How to have an enum value in CommandParam in XAML

I have the following enum that represent a state of UI (I use it to enable and disable UI elements):
enum Mode
{
EDIT, RUN, REVIEW
}
I would like to pass Mode.EDIT to command in CommandParam:
<Button Grid.Column="6" VerticalAlignment="Top Command="{Binding Path=ChangeMode}"
CommandParameter="{StaticResource local:Mode.RUN}" />
But I have no idea how to declare it. As you see in the button declaration, I try to use StaticResource but it fails. I am quite new to SL4 and C# so I suppose that I missed something.
I have found a solution. I have created in my MyViewModel (my DataContext) 3 public attributes (of type Mode) and initialize them in the constructor (with values EDIT, RUN, REVIEW). Next, I have bound them in XAML as a normal property of a DataContext:
CommandParameter="{Binding Path=EDIT}
class MyViewModel
{
public Mode EDIT {set; get;}
public Mode RUN {set; get;}
public Mode REVIEW {set; get;}
MyViewModel()
{
EDIT = Mode.EDIT;
...
}
}
In WPF we can do something like this (might not work in SL) -
<Button Grid.Column="6" Command="{Binding Path=ChangeMode}"
CommandParameter="{x:Static local:Mode.RUN}" />
check this question for more details -
Passing an enum value as command parameter from XAML
in silverlight x:Static doesn't work so we can do sth like this:
<Button Command="{Binding Path=ChangeMode}">
<Button.CommandParameter>
<Mode>RUN</Mode>
</Button.CommandParameter>
</Button>