Silverlight4 DataTemplates - silverlight-4.0

I have a ItemsControl with its ItemsSource bound to a collection, additionally I have a ItemTemplateSelector set.
It works well however the DataTemplateSelector only allows me to access the items bound by ItemsSource, however I want to use the Parents DataContext to make the decision on what item template should be used.
Is this achievable in SL4??
If so how can it be achieved??

Thanks for your response #Xin but I managed to resolve my problem by doing the following.
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
DataTemplate dt = null;
switch ((DataContext as PlanViewModel).Plan.Status)
{
case Infrastructure.Services.Web.PlanStatus.Appraisal:
dt = (DataTemplate)this.Resources["Appraisal"];
break;
case Infrastructure.Services.Web.PlanStatus.Maintenance:
dt = (DataTemplate)this.Resources["Maintenance"];
break;
case Infrastructure.Services.Web.PlanStatus.Setting:
dt = (DataTemplate)this.Resources["Setting"];
break;
}
itemsControl1.ItemTemplate = dt;
}

Yes it is.
Name your layout root 'LayoutRoot', then you can do
<TextBlock Text="{Binding DataContext.SomeTextInParent, ElementName=LayoutRoot}" />
in your item template.

Related

How to do the equivalent of {Binding Source} in code?

I'm extending a control to be able to reuse it across my current Xamarin project. As part of this control, I need to create a DataTemplate programmatically. I have this part figured out and it works ok.
The DataTemplate has a Label in it. I need to bind the Label's BindingContext property to {Binding Source}. I need to bind the Label's Text property to {Binding Path=Name}.
This works in XAML, but I don't want to have to copy it to a million different places in the code base.
<dxGrid:TemplateColumn FieldName="MyPropertyName"
Caption="MyColumn">
<dxGrid:TemplateColumn.DisplayTemplate>
<DataTemplate>
<Label BindingContext="{Binding Source}"
Text="{Binding Source, Path=MyPropertyName}" />
</DataTemplate>
</dxGrid:TemplateColumn.DisplayTemplate>
My extended control looks like this right now:
public class MyColumn : TemplateColumn
{
public MyColumn()
{
DataTemplate displayTemplate = new DataTemplate(() =>
{
BindingBase textBinding = new Binding(FieldName);
Label label = new Label();
// TODO: Bind BindingContextProperty to {Binding Source}
//label.SetBinding(BindingContextProperty, binding);
label.SetBinding(Label.TextProperty, textBinding);
return new ViewCell
{
View = label
};
});
DisplayTemplate = displayTemplate;
}
}
I'm getting hung up in the binding because I'm not sure how to do the equivalent of {Binding Source} in code. Any help would be appreciated.
#Eugene - Thanks for the response. Unfortunately this does not work and binding to "Source" like that throws a Null Reference Exception. I made another pass at it this morning and got it working this way:
public MyColumn()
{
DataTemplate displayTemplate = new DataTemplate(() =>
{
Grid grid = new Grid();
grid.SetBinding(Grid.BindingContextProperty, "Source");
Label label = new Label();
label.SetBinding(Label.TextProperty,FieldName);
grid.Children.Add(label);
return grid;
});
this.DisplayTemplate = displayTemplate;
}
It's simple, use name of property
label.SetBinding(BindingContextProperty, "Source");

Listview and Drag Item Windows Phone 8.1

I'm scruiggling with Windows Phone behavior. And maybe you could help me out somehow.
I want to have a listview from which I can drag items to another Gridview.
So far I got dragging enabled by setting ReorderMode = "Enabled". Doing this has some drawbacks.
1. I'm not able to scroll in my listview anymore
2. I can't select items anymore
3. I don't want the items to be reordered
What I want to have:
1. When holding an item, I want to drag this to another gridview
2. I want still be able to scroll in the listview
3. I still want to be able to select items
Is that somehow possible to do in Windows Phone 8.1?! Can I do my own dragging? Is yes, how should I start?!
Many thanks for any advise
ReorderMode isn't want you want in this case. Here's some basic functionality to do this between two ListViews:
<StackPanel Orientation="Horizontal" Width="800">
<ListView x:Name="ListView1" HorizontalAlignment="Left" DragItemsStarting="ListView_DragItemsStarting" AllowDrop="True" CanDragItems="True" CanReorderItems="True" Drop="ListView_Drop"/>
<ListView x:Name="ListView2" HorizontalAlignment="Right" DragItemsStarting="ListView_DragItemsStarting" AllowDrop="True" CanDragItems="True" CanReorderItems="True" Drop="ListView_Drop"/>
</StackPanel>
ObservableCollection<string> AlphabetList;
ObservableCollection<string> NumberList;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
AlphabetList = new ObservableCollection<string>();
AlphabetList.Add("A");
AlphabetList.Add("B");
AlphabetList.Add("C");
AlphabetList.Add("D");
AlphabetList.Add("E");
AlphabetList.Add("F");
AlphabetList.Add("G");
AlphabetList.Add("H");
AlphabetList.Add("I");
AlphabetList.Add("J");
ListView1.ItemsSource = AlphabetList;
NumberList = new ObservableCollection<string>();
NumberList.Add("0");
NumberList.Add("1");
NumberList.Add("2");
NumberList.Add("3");
NumberList.Add("4");
NumberList.Add("5");
NumberList.Add("6");
NumberList.Add("7");
NumberList.Add("8");
NumberList.Add("9");
ListView2.ItemsSource = NumberList;
}
IList<object> DraggedItems;
private void ListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
DraggedItems = e.Items;
}
private void ListView_Drop(object sender, DragEventArgs e)
{
ListView ThisListView = sender as ListView;
ObservableCollection<string> AddingOC = (ThisListView.Name == "ListView1" ? AlphabetList :NumberList);
ObservableCollection<string> RemovingOC = (ThisListView.Name == "ListView1" ? NumberList : AlphabetList);
if (AddingOC.Contains(DraggedItems[0])) return;
foreach (string O in DraggedItems)
{
RemovingOC.Remove(O);
AddingOC.Add(O);
}
}

ListView Not updating if a delete an item

I have a listView which is set to Mode=TwoWay, which i thought was suppose to refresh the views, if the underlying data changed.
However, while the item is deleted correctly, the item still remains on the list, until I exit and return to the page.
Xaml:
<ListView ItemsSource="{Binding Path=items, Mode=TwoWay}" >
<DataTemplate>
...
<Button x:Name="btn_delete_item" Click="btn_delete_item_Click" >
</Button>
Behind code:
private void btn_delete_item_Click(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
itemType item = button.DataContext as itemType;
items.Remove(item);
}
In order to fully support data binding, your Items collection must notify about changes, i.e. whether items are added, removed, replaced or moved. This notification is done by implementing the INotifyCollectionChanged interface. The framework's List<T> type does not implement this interface, but ObservableCollection<T> does.
So you could simply change the type of your Items property:
public ObservableCollection<ItemType> Items { get; set; }

Blend 4 Passing Data Context with Navigate To

I have a list of customers with various pieces of information. I have a list box with their names. When I select an entry I see more information about the customer on the screen. I want to "Navigate To" another screen when clicking on the user's name with more of their information. I can't figure out how to pass information about the entry to the next screen to accomplish this.
Here is the list box that the user chooses from to begin with.
<ListBox x:Name="scheduleListBox"
ItemTemplate="{DynamicResource ItemTemplate}"
ItemsSource="{Binding Collection}"
Margin="8,8,8,0"
Style="{DynamicResource ListBox-Sketch}"
Height="154"
VerticalAlignment="Top"/>
Here is the TextBlock that could be clicked to go to the other screen. It is changed based on what the user selected from the ListBox.
<TextBlock Text="{Binding Customer}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="150" Margin="104,0,0,0"
Style="{DynamicResource BasicTextBlock-Sketch}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<pi:NavigateToScreenAction TargetScreen="V02Screens.Customer_Status"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
I'm kind of hoping that there is something I can do in Expression Blend 4 or in the XAML.
In Windows 8, you can pass the entire object to the receiving page.
Like this:
// main page
private void ListBox_SelectionChanged_1
(object sender, SelectionChangedEventArgs e)
{
var _Item = (sender as ListBox).SelectedItem;
Frame.Navigate(typeof(MainPage), _Item);
}
// detail page
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.DataContext = e.Parameter;
}
In WPF & SL, you can save reference to the SelectedItem in your View Model.
// main page
private void ListBox_SelectionChanged_1
(object sender, SelectionChangedEventArgs e)
{
var _Item = (sender as ListBox).SelectedItem;
MyModel.SelectedItem = _Item;
// TODO: navigate
}
// detail page
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.DataContext = MyModel.SelectedItem;
}
I hope this helps.
In WPF you can supply an object to the Navigate command which contains anything you want, including whatever data you might want to show on the next page. Then on the target page (the one you navigate to), you have to handle the load completed event.
In your first page you might navigate with...
this.NavigationService.Navigate( somePage, someContainerObject );
Then you might retrieve it on somePage with...
// Don't forget to subscribe to the event!
this.NavigationService.LoadCompleted += new LoadCompletedEventHandler(container_LoadCompleted);
...
void container_LoadCOmpleted( object sender, NavigationEventArgs e)
{
if( e.ExtraData != null )
// cast e.ExtraData and use it
}

How to set SelectedItem for a ColumnSeries chart from the ViewModel

I have a ColumnSeries chart where I want to control the selected item from the view model. I do this by binding the the SelectedItem of the chart to an object on the view model.
<chartingToolkit:Chart Grid.Row="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" BorderThickness="0" MinHeight="200" Margin="0" x:Name="ratingsChart" Style="{StaticResource ChartWithoutLegendStyle}">
<chartingToolkit:Chart.Series>
<chartingToolkit:ColumnSeries x:Name="chartRatingColSeries" IsSelectionEnabled="True"
SelectedItem="{Binding SelectedRatingDistribution, Mode=TwoWay}"
ItemsSource="{Binding RatingsList}"
IndependentValueBinding="{Binding RatingName}"
DependentValueBinding="{Binding NumberOfGoodies}">
</chartingToolkit:ColumnSeries>
</chartingToolkit:Chart.Series>
</chartingToolkit:Chart>
There are various elements on the page which will force the chart's data to be reloaded (via a web service). When I need to reload the charts data (from the view model), I want to set the SelectedItem of the chart to the very first data point. This appears to work EXCEPT the chart does not visually show (in red, by default) the selected item. Here is sample code that reloads data after web service call and resets selected item:
private RatingDistribution _selectedRatingDistribution = new RatingDistribution();
public RatingDistribution SelectedRatingDistribution
{
get { return _selectedRatingDistribution; }
set
{
_selectedRatingDistribution = value;
RaisePropertyChanged("SelectedRatingDistribution");
}
}
private ObservableCollection<RatingDistribution> _lstRatings = new ObservableCollection<RatingDistribution>();
public ObservableCollection<RatingDistribution> RatingsList
{
get { return _lstRatings; }
set
{
_lstRatings = value;
RaisePropertyChanged("RatingsList");
}
}
private void GetRatingsDistributionCompleted(object sender, GetRatingsDistributionCompletedEventArgs e)
{
IsBusy = false;
RatingsList.Clear();
foreach (RatingDistribution rd in e.Result)
RatingsList.Add(rd);
SelectedRatingDistribution = RatingsList[0];
}
Setting the SelectedRatingDistribution from the View model will not visually show the selected item on the chart in red. Any ideas??
Update:
So if I click on a column, the chart correctly shows the selected item in red as so:
But If I set the SelectedItem from view model, the column will not be displayed in red (as the selected item)
Changed function below fixes problem..
private void GetRatingsDistributionCompleted(object sender, GetRatingsDistributionCompletedEventArgs e) {
RatingsList.Clear();
foreach (RatingDistribution rd in e.Result)
RatingsList.Add(rd);
App.Current.RootVisual.Dispatcher.BeginInvoke(new Action(delegate() { SelectedRatingDistribution = RatingsList[0]; }));
}