Accessing a ProgressBar within a ListBox of buttons - windows-phone-7

I want to be able to control when I will show a ProgressBar based on a click event. Normally this would be fine, except that I don't believe I can access the ProgressBar since it is so nested in with this structure.
The following code sample shows the structure I Have
<ListBox Name="AudioListBox" Margin="12,0,0,0" Grid.Row="2" Width="396" HorizontalAlignment="Left" ItemsSource="{Binding Audio}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button BorderThickness="0.0" Click="ChapterPlayerButtonClick" Style="{StaticResource ButtonStyle1}">
<StackPanel Name="ButtonsStackPanel" Margin="0,0,0,17">
<TextBlock Foreground="{Binding ChapterForeground}" Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextLargeStyle}"/>
<ProgressBar x:Name="MyProgressBar" Value="{Binding ChapterProgressPosition}" Visibility="Collapsed"
IsIndeterminate="False" Foreground="{Binding ChapterForeground}" Width="300" Background="Black" HorizontalAlignment="Left">
</ProgressBar>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this example, I want to be able to change the visbility of this progress bar, as well as bind it to update with a timer I have set up. Unfortunately I can't find a way to turn on the visbility for the progress bar on the button click.

This is where MVVM can really help - you've already got a data binding to your ViewModel presumably from looking at your XAML.
You can send a message to your ViewModel to turn on the progress bar, by changing a IsProgressBarVisible property on your ViewModel.
Then you can bind to this boolean in your ViewModel using a VisibilityValueConverter (see post by Jeff Wilcox at this link for more details).
<ProgressBar
x:Name="MyProgressBar"
Visibility="{Binding IsProgressBarVisible, Converter={StaticResource VisibilityConverter}}"
IsIndeterminate="{Binding IsIndeterminate}"
...
</ProgressBar>

If you want to update bound items within the ItemTemplate you'll need to update the bindings as you can't refer to instances of such items by name. (Because you can't have multiple items with the same name.)
In the Click event handler you can access the viewmodel instance via the sender and manipulate the properties there.
For example, the following will increment the value of the progress bar each time the button is tapped/clicked.
private void ChapterPlayerButtonClick(object sender, RoutedEventArgs e)
{
((sender as FrameworkElement).DataContext as ItemVm).ChapterProgressPosition++;
}
Note that due to a "quirk" of the ProgressBar you'll need to enable TwoWay binding to update the Value via binding.
I'm sure you can work out how to do the rest.
You'll need to bind the Visibility if you want to alter that too.
As an alternative solution I'd replace the button click event with a RelayCommand on the ViewModel itself to simplify the code. You could then put all the logic in the same place and not require all the casting as in the click event handler above.

Related

CheckBox Checked and Unchecked Event fires when scrolling a Listbox in windows phone 8 app?

I am developing a Windows Phone 8 App in which I am using a checkbox inside a listbox along with some textblocks.
<ListBox x:Name="lstStudentSelect" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" Background="Transparent" ScrollViewer.VerticalScrollBarVisibility="Visible" Height="487" BorderThickness="0" VerticalAlignment="Top" Margin="8,198,10,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel Width="360" Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Text="{Binding stunum}" Width="80" Foreground="Black" TextWrapping="Wrap" FontSize="20" VerticalAlignment="Center" />
<TextBlock Text="{Binding name}" Width="280" Foreground="Black" TextWrapping="Wrap" FontSize="20" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Width="5"></StackPanel>
<StackPanel Width="150" Orientation="Horizontal" HorizontalAlignment="Right">
<CheckBox IsChecked="{Binding ChkFlag, Mode=TwoWay}" BorderBrush="#203485" Foreground="Black" BorderThickness="1" Tag="{Binding cusnum}" Name="cusCheck" Checked="cusCheck_Checked_2" Unchecked="cusCheck_Unchecked_2" ></CheckBox>
<TextBlock Text=" " TextWrapping="Wrap" Foreground="Black" FontSize="20" VerticalAlignment="Center" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
when I check/select on the checkbox the checkbox checked event fires, when I uncheck/unselect a checkbox the checkbox unchecked event fires.
But now my issue is :
When I am scrolling the listbox the checkbox checked and unchecked event fires automatically ?
How can I avoid this to happen ?
Your issue relates to the fact you are binding the IsChecked property and have handlers for the Checked and Unchecked events. When the binding is updated and the property changes this will cause the events to fire.
Events will fire for each item when the ItemsSource is set/loaded.
By default the ListBox uses a virtualizing container for it's item panel. This means that as you scroll items will be loaded in and out of the container and this will also trigger events as a result of the binding changing. This is why you will see more events being triggered while you scroll. (Assuming you have a sufficiently large list to require virtualization.)
Assuming that ChkFlag is a property on your ViewModel and cusCheck_Checked_2 & cusCheck_Unchecked_2 are event handlers on your view, you could make things simpler for yourself and avoid this issue by moving the logic from the event handlers into the setter for ChkFlag. (This will probably also improve ease of testability too.)
For example, you could have a property like this:
public bool ChkFlag
{
get
{
return this.chkFlagField;
}
set
{
if (this.chkFlagField != value)
{
this.chkFlagField = value;
this.RaisePropertyChanged();
if (value)
{
// perform checked action
}
else
{
// perform unchecked action
}
}
}
}
An alternative solution can be set a StackPanel as Panel.
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>

WP7 Databind with Pivot - Not sure where I'm going wrong

Edit:
Worked out the problem - see accepted answer for a good explanation!
My XAML now looks like this:
<controls:Pivot x:Name="MainPivot" Title="FYP APP" ItemsSource="{Binding Cuisines}">
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Cuisine}"/>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Outlets}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="78">
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding Cuisine}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
Original:
I'm building a Pivot page using the sample one provided with VS.
I have a list of restaurants, which I would like to be able to filter by swiping the pivot left/right (e.g. http://img831.imageshack.us/img831/514/pivotm.jpg).
I have a list of all restaurants in App.xaml.cs (public static ObservableCollection<OutletViewModel> LocalOutlets which is filled from the MainPage constructor), and this is then processed to create this structure:
OutletListPage2.xaml.cs (the page I'm working on) sets the DataContext to a new OutletsByCuisineViewModel().
OutletsByCuisineViewModel has a public ObservableCollection<CuisineViewModel> Cuisines, which contains a CuisineViewModel for each cuisine (including an "all" one).
A CuisineViewModel has a public string Cuisine, and a public ObservableCollection<OutletViewModel> Outlets.
An OutletViewModel contains a public string Name and a public string Cuisine - each triggering the PropertyChanged event.
The design sample data I want to use is: (also, I can't specify the same outlet multiple times in this file - VS says Name XYZ already exists in the current name scope)
<local:OutletsByCuisineViewModel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:FYP.ViewModels">
<local:OutletsByCuisineViewModel.Cuisines>
<local:CuisineViewModel Cuisine="all">
<local:CuisineViewModel.Outlets>
<local:OutletViewModel Name="Test1" Cuisine="fast food" />
<local:OutletViewModel Name="Test2" Cuisine="indian" />
<local:OutletViewModel Name="Test3" Cuisine="pizza" />
</local:CuisineViewModel.Outlets>
</local:CuisineViewModel>
<local:CuisineViewModel Cuisine="fast food">
<local:CuisineViewModel.Outlets>
<local:OutletViewModel Name="Test1a" Cuisine="fast food" />
</local:CuisineViewModel.Outlets>
</local:CuisineViewModel>
<local:CuisineViewModel Cuisine="indian">
<local:CuisineViewModel.Outlets>
<local:OutletViewModel Name="Test2a" Cuisine="indian" />
</local:CuisineViewModel.Outlets>
</local:CuisineViewModel>
<local:CuisineViewModel Cuisine="pizza">
<local:CuisineViewModel.Outlets>
<local:OutletViewModel Name="Test3a" Cuisine="pizza" />
</local:CuisineViewModel.Outlets>
</local:CuisineViewModel>
</local:OutletsByCuisineViewModel.Cuisines>
</local:OutletsByCuisineViewModel>
I have the following in the XAML designer - http://img844.imageshack.us/img844/8464/pivot2.jpg
I've not been able to find anything online which might help, possibly because I'm not sure what's wrong.
Any suggestions or pointers would be greatly appreciated :)
Looking at the last screenshot - when you set the ItemsSource property, Pivot ignores the collection of PivotItems that you specify explicitly and generates a new one based on the ItemsSource collection.
So you can try to remove PivotItem declaration and use ItemsSource only, bind it to the collection of your view models and use a combination of Pivot.ItemTemplate and Pivot.ItemContainerStyle properties to style pivot items properly (set header and content).

How to do the binding in this case?

As the code below shows, I have a Canvas with a TextBlock inside. Next to it, two textBlocks, their text properties binded to LineOne and LineTwo, ObservableCollection variables. What I want is to create a binding which gives the date and change the color of the Canvas accordingly.
Theoretically, I can bind the date change for the Text property of the DateTextBlock. But I am not sure how to do the color change of the Canvas.
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17">
<!--Replace rectangle with image-->
<Canvas Width="100" Height="100" Background="YellowGreen">
<StackPanel>
<TextBlock Name="DateTextBlock" Text="16 May" HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</Canvas>
<StackPanel Width="311">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
Kindly advise me.
Thanks,
Create a colour property on the view model, and a property changed notifier. Bind the view attribute to the Colour property. In the viewmodel, when the text changes (or whatever it is you want to trigger the colour change), update the Colour property with the appropriate colour making sure to use the public property so that the change event fires.
The Canvas Background property is of type Brush. Therefore, you are either going to have to bind a property of type Brush to Canvas.Background, or you can use a ValueConverter to convert a moel property to a Brush. See the examples on this page:
http://compiledexperience.com/blog/posts/useful-calue-converters

Why does stackpanel break my pivotviewer?

I have a working pivotviewer with 128 images of cars that I put together myself. I used one of the many tutorials on the web to get it working, and it works well. Then I thought I should decorate the page a bit so I put the grid in which the pv resided inside a bounding stackpanel with a couple of textblocks above it to tell what the collection is. Everything loads fine except the images. Comment out the stackpanel lines and it works perfectly.
Any ideas? How could something so simple fail?
Here is all of the code in MainPage.xaml:
<StackPanel>
<TextBlock
FontSize="24"
HorizontalAlignment="Center"
VerticalAlignment="Top">
Silverlight Pivotviewer Example
</TextBlock>
<TextBlock
FontSize="16"
HorizontalAlignment="Center"
VerticalAlignment="top">
Cool Automobiles
</TextBlock>
<Grid x:Name="LayoutRoot" Background="White">
<pivoter:PivotViewer x:Name="pivotViewer" />
</Grid>
</StackPanel>
Your Grid, "LayoutRoot", is your main layout control. You need to wrap your StackPanel within the Grid control.
Something like this:
<Grid x:Name="LayoutRoot" Background="White"
<StackPanel>
<TextBlock
FontSize="24"
HorizontalAlignment="Center"
VerticalAlignment="Top">
Silverlight Pivotviewer Example />
<TextBlock
FontSize="16"
HorizontalAlignment="Center"
VerticalAlignment="top">
Cool Automobiles />
<pivoter:PivotViewer x:Name="pivotViewer" />
</StackPanel>
</Grid>
After your declaration of your Grid, I would add some rows, i.e. 0, 1, 2. Then I would layout your Stackpanels, PivotViewer, etc.
Hope this helps.
This is a known issue. The StackPanel is a dimensionless element. You need to add Width and Height values to the StackPanel and the PivotViewer will begin working correctly.
This is what we did. We added an event handler to the SizeChanged event on the dialog then sized the PivotViewer. Also after the Initialise or Loaded event call it too...see how you go?
void PivotDialog_SizeChanged( object sender, SizeChangedEventArgs e )
{
SizePivotViewer( );
m_PivotViewer.UpdateLayout( );
}
private void SizePivotViewer( )
{
m_PivotViewer.Width = ActualWidth;
m_PivotViewer.Height = ActualHeight - 20; // Magic number so text will display properly at bottom of Pivot!
}

Custom Toggleswitch with binding to object

I am trying to create a toggleswitch which will have multiple rows in the datatemplate bound to different properties of a single object. These toggleswitches will be inside a listbox.
My xaml code below shows the current toggleswitch template. With the code below, only the header is binding properly. I need the other two rows (in the ContentTemplate) and the toggleswitch itself to bind to a boolean property of the object.
<DataTemplate>
<toolkit:ToggleSwitch Header="{Binding Property1}" Width="450">
<toolkit:ToggleSwitch.HeaderTemplate>
<DataTemplate>
<ContentControl FontWeight="Black" FontSize="40" Foreground="{StaticResource PhoneForegroundBrush}" Content="{Binding}" VerticalAlignment="Top" />
</DataTemplate>
</toolkit:ToggleSwitch.HeaderTemplate>
<toolkit:ToggleSwitch.ContentTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Property2}" FontSize="32" FontWeight="Light" Foreground="{StaticResource PhoneAccentBrush}" />
<TextBlock Text="{Binding Property3}" FontSize="{StaticResource PhoneFontSizeSmall}" Foreground="{StaticResource PhoneSubtleBrush}" />
</StackPanel>
</DataTemplate>
</toolkit:ToggleSwitch.ContentTemplate>
</toolkit:ToggleSwitch>
</DataTemplate>
Any advice here on how to achieve the results I need?
Thanks in advance!
Here is what I am trying to achieve
Property1
Property2:On/Off [===] (this is the toggle switch)
Property3
Properties 1,2, and 3 all will have custom formatting as well. Please keep in mind these will be in a listbox, so they will be binding to a collection.
You'll need to modify the source of the ToggleSwitch in the converter.
Add extra text/string properties to have something to bind Property2 and Property3 to. (These will also need to be separate items to be templated differently- like in the alarms app.)
Then look at changing the binding for the ContentProperty or extend the OffOnConverter to include the additional new proprties.
Probably, what you need is binding to an element, check this post:
Silverlight 3 Element binding in a datatemplate
Give the element with data template x:Name property and then use element binding from within data template.
Hope this helps,
Robert

Resources