How to set SelectedItem for a ColumnSeries chart from the ViewModel - silverlight-4.0

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]; }));
}

Related

Xamarin picker, not setting default value

I've got a picker on the screen, that has an initial value, as well as the option to change the item in the picker.
While my selectedItem is set, I don't see that on the picker on the screen, the picker has no value set, and it's not until I select a value, that it actually displays something in the picker on the screen (At this time the SelectedItem is also updated with the new value).
My xaml:
<Picker
ItemsSource="{Binding FeedbackTypes}"
SelectedItem="{Binding SelectedFeedbackType, Mode=TwoWay}"
ItemDisplayBinding="{Binding Name}">
</Picker>
My ViewModel properties:
private ValueName _selectedFeedbackType;
public ValueName SelectedFeedbackType
{
get { return _selectedFeedbackType; }
set
{
_selectedFeedbackType = value;
OnPropertyChanged(nameof(SelectedFeedbackType));
}
}
public ObservableCollection<ValueName> FeedbackTypes
{
get
{
var feedbackTypes = new ObservableCollection<ValueName>();
foreach (FeedbackType feedback in
Enum.GetValues(typeof(FeedbackType)))
{
feedbackTypes.Add(new ValueName
{
Value = feedback,
Name = feedback.ToName()
});
}
return feedbackTypes;
}
}
And in my ViewModel constructor I've got:
SelectedFeedbackType = new ValueName { Value = feedbackType, Name = feedbackType.ToName() };
The constructor works sets the SelectedFeedbackType correctly and if I don't make any changes to the picker, that is the value I get in there on submit, however, I do not see that value in the picker by default. The picker is empty until a selection is made.
I've also tried to bind the SelectedIndex value to the SelectedFeedbackType, however that one will not show the initially selected value either in the picker.
You could try to set defalut value of the Xamarin Picker.
You just set the selectedIndex(the first number of index is 0) of your picker like the following code.
Mypicker.SelectedIndex=1;
There is a code of demo.
GIF of demo when first running.
You can download this demo by the link.
https://developer.xamarin.com/samples/xamarin-forms/UserInterface/PickerDemo/
Then changed the code of MonkeysPage.xaml.
<Picker x:Name="Mypicker" Title="Baboon" ItemsSource="{Binding Monkeys}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding SelectedMonkey}" />
Add the defaule value of Pickerin MonkeysPage.xaml.cs.
public MonkeysPage()
{
InitializeComponent();
BindingContext = new MonkeysPageViewModel();
Mypicker.SelectedIndex=1;
}
}

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; }

Notify ListBox and ListBox Item for CRUD from Background Thread

I'm working with LINQ/SQL within my WP8 app to manage a collection of items that are shown within a ListBox.
Sometimes one these objects is changed by a long runned operation using another DataContext.
These changes could be one of the CRUD operations, so objects can be created in the background, too.
In iOS there is the NSFetchedResultsController for it or i can use a NSNotification - i'm searching for something similar.
update some code for an updating case
I'm fetching my items like this:
void loadData() {
var items = from r in itemDB.items orderby r.UpdatedAt descending select r;
var Items = new ObservableCollection<Item>(items);
lstData.ItemsSource = Items;
}
my listBox looks like this
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding LocalState}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and my background code looks like this:
static public void UploadAll() {
ThreadPool.SetMaxThreads(1,1);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
}
static void ThreadProc(Object stateInfo)
{
ItemsContext itemsDB = new ItemsContext(ItemsContext.DBConnectionString);
var notUploadedItems = (from i in itemsDB.items
where !i.LocalState.Equals("server")
select i);
var Items = new ObservableCollection<Item>(notUploadedItems);
foreach (Item a in Items)
{
a.Save(() =>
{
Deployment.Current.Dispatcher.BeginInvoke(delegate
{
a.LocalState = "server";
itemsDB.SubmitChanges();
});
//NOW THE LISTBOX SHOULD BE UPDATED
}, (err) =>
{
});
}
}
at the //NOW THE LISTBOX SHOULD BE UPDATEDcomment, the corresponding listbox template should be updated
add/delete cases are similar.
cheers.
To be straight to the point, creating new instance of the ObservableCollection every time your data changes then re-assigning it to the ItemSource, is not only disregarding core purpose of the ObservableCollection, it is also breaking/misusing the concept of Data
Binding.
//this is the line I am talking about:
var Items = new ObservableCollection<Item>(notUploadedItems);
Instead, create the ObserbaleCollection once -- make it a property:
private readonly ObservableCollection<Item> _items = new ObservableCollection<Item>();
public ObservableCollection<Item> Items {get {return _items;}
For the updates use collection's '.Add()' or 'Remove()' methods
You're correct that you must be on the UI Main thread to do the updates:
DoItOnUIThread(() =>Items.Add(newItem));
//here's a sample of method that would take any action and execute it on UI thread..
private void DoItOnUIThread(Action action)
{
if (_dispatchService == null)
_dispatchService = ServiceLocator.Current.GetInstance<IDispatchService>();
if (_dispatchService.CheckAccess())
action.Invoke ();
else
_dispatchService.Invoke(action);
}
Let the observable collection do its job, which is automatically update the UI through Binding with new items and their property changes. If all that is hooked up/done properly your listbox shouldn't need to be updated in cs code at all.

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
}