I have a XAML UserControl which defines a fairly basic button - I want to define a Bindable property HasMeasurements which will display an overlay image when HasMeasurements is false . However when I include it in my project and bind it to the ViewModel it does not update consistently.
I am sure the ViewModel is properly notifying the bindings since I have simultenously bound the same ViewModel property to another separate element and it updates as expected. Also it works in Blend when I update the mock data.
I have tried this solution which defines a callback where I change the Visibility programatically, however this callback is not called every time the ViewModel property changes, only sometimes. I have also tried binding the Visibility in the XAML using this solution and a non dependency property which also did not work. I have also tried implementing NotifyPropertyChanged out of desperation but no luck there either ...
Here is my XAML,
<UserControl x:Class="MyApp.View.Controls.ConversionBtn"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<Grid x:Name="btnGrid" toolkit:TiltEffect.IsTiltEnabled="True" Height="115">
<Border Background="{StaticResource ImgOverlayColor}" BorderThickness="0" Padding="0" VerticalAlignment="Top" >
<TextBlock x:Name="titleTxtBlock" FontSize="{StaticResource PhoneFontSizeMedium}" Foreground="{StaticResource TileTxtColor}" Margin="6,0,0,0"/>
</Border>
<Image x:Name="notAvailableImg" Source="/Images/ConversionNotAvailableOverlay.png" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" />
</Grid>
</Grid>
</UserControl>
Here is the code behind,
// usings here ...
namespace MyApp.View.Controls
{
public partial class ConversionBtn : UserControl
{
public ConversionBtn()
{
InitializeComponent();
if (!TiltEffect.TiltableItems.Contains(typeof(ConversionBtn)))
TiltEffect.TiltableItems.Add(typeof(ConversionBtn));
//this.DataContext = this;
}
public string Title
{
get { return this.titleTxtBlock.Text; }
set { this.titleTxtBlock.Text = value; }
}
public static readonly DependencyProperty HasMeasurementsProperty =
DependencyProperty.Register("HasMeasurements", typeof(bool), typeof(ConversionBtn),
new PropertyMetadata(false, new PropertyChangedCallback(HasMeasurementsPropertyChanged)));
private static void HasMeasurementsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ConversionBtn cBtn = (ConversionBtn)d;
bool val = (bool)e.NewValue;
if (val)
{
cBtn.notAvailableImg.Visibility = Visibility.Collapsed;
}
else
{
cBtn.notAvailableImg.Visibility = Visibility.Visible;
}
cBtn.HasMeasurements = val;
}
public bool HasMeasurements
{
get { return (bool)GetValue(HasMeasurementsProperty); }
set { SetValue(HasMeasurementsProperty, value); }
}
}
}
You have a callback, that is called after HasMeasurment propetry was changed.
And in a callback you change it again. So, you have a logical misstake.
If you need to do something with this value - just save it in private field.
private static void HasMeasurementsPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
ConversionBtncBtn = (ConversionBtn)d;
bool val = (bool)e.NewValue;
if (val)
{
cBtn.notAvailableImg.Visibility = Visibility.Collapsed;
}
else
{
cBtn.notAvailableImg.Visibility = Visibility.Visible;
}
cBtn.SetMeasurments(val);
}
private bool measurmentsState;
public void SetMeasurments(bool value)
{
measurmentsState = value;
}
Here you can get free e-Book by Charls Petzold about Windows Phone Development, there is a nice chapter about Dependency Properties.
Ah damnit, it was a combination of Anton's answer and the fact that I hadn't set my image as 'Content', hence it loaded in Blend but was not present in the deployed app.
Related
There is a question with an answer that shows how a progress bar can be created that runs for a specified period of time. Here's a link to that question:
How can I create a bar area that slowly fills from left to right over 5, 10 or ?? seconds?
I have tested this out and it works well. However I would like to find out how I can extend this so that the progress bar can be cancelled / stopped before completed and then restarted again.
The question and answer were very popular so it seems like this is something that might benefit many people.
I would appreciate any ideas and feedback on possible ways this could be done.
Update 1:
I tried to implement the solution but I am getting an error and would appreciate some advice. I'm using all your new code and I change from the old to the new here:
<local:TimerView x:Name="timerView">
<local:TimerView.ProgressBar>
<BoxView BackgroundColor="Maroon" />
</local:TimerView.ProgressBar>
<local:TimerView.TrackBar>
<BoxView BackgroundColor="Gray" />
</local:TimerView.TrackBar>
</local:TimerView>
<!--<Grid x:Name="a">
<local:TimerView x:Name="timerView1" VerticalOptions="FillAndExpand">
<local:TimerView.ProgressBar>
<Frame HasShadow="false" Padding="0" Margin="0" BackgroundColor="#AAAAAA" CornerRadius="0" VerticalOptions="FillAndExpand" />
</local:TimerView.ProgressBar>
<local:TimerView.TrackBar>
<Frame HasShadow="false" Padding="0" Margin="0" CornerRadius="0" BackgroundColor="#EEEEEE" VerticalOptions="FillAndExpand" />
</local:TimerView.TrackBar>
</local:TimerView>
</Grid>
<Grid x:Name="b">
<local:TimerView x:Name="timerView2" VerticalOptions="FillAndExpand">
<local:TimerView.ProgressBar>
<Frame HasShadow="false" Padding="0" Margin="0" BackgroundColor="#AAAAAA" CornerRadius="0" VerticalOptions="FillAndExpand" />
</local:TimerView.ProgressBar>
<local:TimerView.TrackBar>
<Frame HasShadow="false" Padding="0" Margin="0" CornerRadius="0" BackgroundColor="#EEEEEE" VerticalOptions="FillAndExpand" />
</local:TimerView.TrackBar>
</local:TimerView>
</Grid>-->
Three questions
First - I noticed you split timerView into two files. The properties file appears to be in some way linked to the main file. Graphically the properties file appears indented from timerView. How do you do this linking in Visual Studio? I just created two files, does that make a difference.
Second - When I try to compile the code I am getting this error:
/Users//Documents/Phone app/Japanese7/Japanese/Views/Phrases/PhrasesFrame.xaml(10,10): Error: Position 117:10. Missing a public static GetProgressBar or a public instance property getter for the attached property "Japanese.TimerView.ProgressBarProperty" (Japanese)
Do you have any ideas what might be causing this? Everything looks the same as before.
Third - I notice you use BoxView and I used a Frame. Would the code work with either?
Update 2:
In my backend C# code I use the following to start the timer:
timerView.StartTimerCommand
.Execute(TimeSpan.FromSeconds(App.pti.Val()));
I tried to stop the timer with some similar syntax but there's some problem. Can you let me know how I can go about stopping the timer when it's used with C# back-end rather than the MVVM in your solution:
timerView.StopTimerCommand.Execute(); // Give syntax error
Step 1: Add cancel method to ViewExtensions:
public static class ViewExtensions
{
static string WIDTH_ANIMATION_NAME = "WidthTo";
public static Task<bool> WidthTo(this VisualElement self, double toWidth, uint length = 250, Easing easing = null)
{
...
}
public static void CancelWidthToAnimation(this VisualElement self)
{
if(self.AnimationIsRunning(WIDTH_ANIMATION_NAME))
self.AbortAnimation(WIDTH_ANIMATION_NAME);
}
}
Step 2: Add bindable properties for 'pause' and 'stop'/'cancel' commands; and a property to track whether timer is running.
public static readonly BindableProperty PauseTimerCommandProperty =
BindableProperty.Create(
"PauseTimerCommand", typeof(ICommand), typeof(TimerView),
defaultBindingMode: BindingMode.OneWayToSource,
defaultValue: default(ICommand));
public ICommand PauseTimerCommand
{
get { return (ICommand)GetValue(PauseTimerCommandProperty); }
set { SetValue(PauseTimerCommandProperty, value); }
}
public static readonly BindableProperty StopTimerCommandProperty =
BindableProperty.Create(
"StopTimerCommand", typeof(ICommand), typeof(TimerView),
defaultBindingMode: BindingMode.OneWayToSource,
defaultValue: default(ICommand));
public ICommand StopTimerCommand
{
get { return (ICommand)GetValue(StopTimerCommandProperty); }
set { SetValue(StopTimerCommandProperty, value); }
}
public static readonly BindableProperty IsTimerRunningProperty =
BindableProperty.Create(
"IsTimerRunning", typeof(bool), typeof(TimerView),
defaultBindingMode: BindingMode.OneWayToSource,
defaultValue: default(bool), propertyChanged: OnIsTimerRunningChanged);
public bool IsTimerRunning
{
get { return (bool)GetValue(IsTimerRunningProperty); }
set { SetValue(IsTimerRunningProperty, value); }
}
private static void OnIsTimerRunningChanged(BindableObject bindable, object oldValue, object newValue)
{
((TimerView)bindable).OnIsTimerRunningChangedImpl((bool)oldValue, (bool)newValue);
}
Step 3: Update TimerView as below to use a StopWatch to track time, pause, and cancel.
public partial class TimerView : AbsoluteLayout
{
readonly Stopwatch _stopWatch = new Stopwatch();
public TimerView()
{
...
}
async void HandleStartTimerCommand(object param = null)
{
if (IsTimerRunning)
return;
ParseForTime(param);
if (InitRemainingTime())
_stopWatch.Reset();
SetProgressBarWidth();
IsTimerRunning = true;
//Start animation
await ProgressBar.WidthTo(0, Convert.ToUInt32(RemainingTime.TotalMilliseconds));
//reset state
IsTimerRunning = false;
}
void HandlePauseTimerCommand(object unused)
{
if (!IsTimerRunning)
return;
ProgressBar.CancelWidthToAnimation(); //abort animation
}
void HandleStopTimerCommand(object unused)
{
if (!IsTimerRunning)
return;
ProgressBar.CancelWidthToAnimation(); //abort animation
ResetTimer(); //and reset timer
}
protected virtual void OnIsTimerRunningChangedImpl(bool oldValue, bool newValue)
{
if (IsTimerRunning)
{
_stopWatch.Start();
StartIntervalTimer(); //to update RemainingTime
}
else
_stopWatch.Stop();
((Command)StartTimerCommand).ChangeCanExecute();
((Command)PauseTimerCommand).ChangeCanExecute();
((Command)StopTimerCommand).ChangeCanExecute();
}
bool _intervalTimer;
void StartIntervalTimer()
{
if (_intervalTimer)
return;
Device.StartTimer(TimeSpan.FromMilliseconds(100), () =>
{
if(IsTimerRunning)
{
var remainingTime = Time.TotalMilliseconds - _stopWatch.Elapsed.TotalMilliseconds;
if (remainingTime <= 100)
{
_intervalTimer = false;
ResetTimer();
}
else
RemainingTime = TimeSpan.FromMilliseconds(remainingTime);
}
return _intervalTimer = IsTimerRunning; //stop device-timer if timer was stopped
});
}
private void ResetTimer()
{
ProgressBar.CancelWidthToAnimation();
RemainingTime = default(TimeSpan); //reset timer
SetProgressBarWidth(); //reset width
}
void SetProgressBarWidth()
{
if (RemainingTime == Time)
SetLayoutBounds(ProgressBar, new Rectangle(0, 0, Width, Height));
else
{
var progress = ((double)RemainingTime.Seconds / Time.Seconds);
SetLayoutBounds(ProgressBar, new Rectangle(0, 0, Width * progress, Height));
}
}
...
}
Sample Usage
<controls:TimerView x:Name="timerView">
<controls:TimerView.ProgressBar>
<BoxView BackgroundColor="Maroon" />
</controls:TimerView.ProgressBar>
<controls:TimerView.TrackBar>
<BoxView BackgroundColor="Gray" />
</controls:TimerView.TrackBar>
</controls:TimerView>
<Label Text="{Binding Path=RemainingTime, StringFormat='{0:%s}:{0:%f}', Source={x:Reference timerView}}" />
<Button Command="{Binding StartTimerCommand, Source={x:Reference timerView}}" Text="Start Timer">
<Button.CommandParameter>
<x:TimeSpan>0:0:20</x:TimeSpan>
</Button.CommandParameter>
</Button>
<Button Command="{Binding PauseTimerCommand, Source={x:Reference timerView}}" Text="Pause Timer" />
<Button Command="{Binding StopTimerCommand, Source={x:Reference timerView}}" Text="Stop Timer" />
Working sample uploaded at TimerBarSample
EDIT 1
First - It really doesn't make a difference - you can even merge all code into one file. Indented linking can be achieved using <DependentOn /> tag - similar to what is used for code-behind cs for XAML files.
Second - I had added protected access-modifiers to bindable properties' getters or setters. But looks like it fails when XAMLC is applied. I have updated the code in the github sample.
Third - Yes, any control that inherits from View (be it be BoxView or Frame) can be used.
EDIT 2
As these commands (bindable properties) are of type ICommand, in order to Execute - you need to pass in a parameter. In case the command doesn't need a parameter - you can use null.
Recommended usage:
if(timerView.StopTimerCommand.CanExecute(null))
timerView.StopTimerCommand.Execute(null);
I set my Pivot's ItemsSource property to a list of 3 URL strings.
Odd things that happen:
With the template below, the ImageOpened event gets called 6 times instead of 3.
If I set the BitmapImage's CreateOptions to 'BackgroundCreation', the ImageOpened event can be called hundreds of times for no apparent reason
If I place the Pivot inside a UserControl and use the 'BackgroundCreation' option for the BitmapImage, then the Images don't render at all inside the Pivot, despite the ImageOpened event getting called (hundreds of times).
The same behaviour happens on WP7 and WP8. I am quite surprised as I was just creating an ImageGallery UserControl that is using a Pivot underneath and I wanted to make use of BackgroundCreation option to offload decoding work to the background thread but with such symptoms it seems quite pointless :(.
1) Pivot
<phone:PhoneApplicationPage
x:Class="WP7.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<Button Tap="UIElement_OnTap">press</Button>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<controls:Pivot x:Name="gallery">
<controls:Pivot.ItemTemplate>
<DataTemplate>
<Image>
<Image.Source>
<BitmapImage ImageOpened="BitmapImage_OnImageOpened" ImageFailed="BitmapImage_OnImageFailed" UriSource="{Binding}" CreateOptions="DelayCreation"></BitmapImage>
</Image.Source>
</Image>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
</Grid>
</Grid>
2) Codebehind
public partial class MainPage : PhoneApplicationPage
{
int c = 0;
List<string> list = new List<string>()
{
"http://d24w6bsrhbeh9d.cloudfront.net/photo/6298284_460s.jpg", "http://d24w6bsrhbeh9d.cloudfront.net/photo/6291760_460s.jpg", "http://d24w6bsrhbeh9d.cloudfront.net/photo/6298282_460s.jpg",
};
// Constructor
public MainPage()
{
InitializeComponent();
}
private void UIElement_OnTap(object sender, GestureEventArgs e)
{
c = 0;
gallery.ItemsSource = list;
}
private void BitmapImage_OnImageOpened(object sender, RoutedEventArgs e)
{
c++;
Debug.WriteLine("opened - {0}", c);
}
private void BitmapImage_OnImageFailed(object sender, ExceptionRoutedEventArgs e)
{
Debug.WriteLine("failed");
}
}
To give you a better idea of what is happening, you can check this snippet:
private void BitmapImage_OnImageOpened(object sender, RoutedEventArgs e)
{
BitmapImage image = (BitmapImage)sender;
Debug.WriteLine("opened - {0}", image.UriSource.ToString());
}
At the very beginning, when you press the button, you will notice what it seems like the first image from your list is loaded twice:
Even if you remove the DelayCreation flag, you will still get the same result because this flag is set by default.
Now, what happens if we inspect this with WireShark, the phone connected to an ad-hoc network:
(NOTE: I am using a different image URL here)
The image is only downloaded once, so per-se you do not need to worry about extra data. The reason why you see it triggered twice seems to be the fact that it is once triggered for the source, and another one for the Image.
Technically, the same if you would do this:
List<BitmapImage> list = new List<BitmapImage>();
// Constructor
public MainPage()
{
InitializeComponent();
BitmapImage image = new BitmapImage();
image.UriSource = new Uri("http://timenerdworld.files.wordpress.com/2012/08/new-microsoft-logo.jpg");
image.ImageOpened += image_ImageOpened;
list.Add(image);
}
void image_ImageOpened(object sender, RoutedEventArgs e)
{
Debug.WriteLine("opened image from bitmap");
}
private void UIElement_OnTap(object sender, GestureEventArgs e)
{
gallery.ItemsSource = list;
}
private void BitmapImage_OnImageOpened(object sender, RoutedEventArgs e)
{
Image image = (Image)sender;
Debug.WriteLine("opened - {0}", ((BitmapImage)image.Source).UriSource.ToString());
}
So no, the image is not downloaded twice.
I have List box in which I am displaying values at runtime. But i want to show an image in list box only when i selected an item from list box.Currently I am using DataTemplate and ItemTemplate in list box for displaying values at runtime (In short data binding).Thanks
One solution is to add a dependency property IsSelected to your item view model, and toggle that when you tap on an item. This would mean that you can select multiple items, i.e. show images from several rows at once.
using some xaml like this:
<phone:PhoneApplicationPage.Resources>
<convert:BooleanToVisibilityConverter x:Key="booltovisibility" />
</phone:PhoneApplicationPage.Resources>
<phone:PhoneApplicationPage.DataContext>
<vm:MainViewModel/>
</phone:PhoneApplicationPage.DataContext>
<Border Grid.Row="1" BorderThickness="1" BorderBrush="Red">
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Green">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding ToggleSelected}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock Grid.Row="0" Text="{Binding Text}"/>
<Image Grid.Row="1" Source="{Binding Image}" Visibility="{Binding IsSelected, Converter={StaticResource booltovisibility}}"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
Note that this xaml uses the System.Windows.Interactivity dll from the Silverlight SDK. It also uses a custom BooleanToVisibilityConverter, which is a IValueConverter that converts a boolean to a Visibility enum value.
Further more, we can define an ItemViewModel like the one below, and have an "Items" property in the MainViewModel
private readonly ObservableCollection<ItemViewModel> items;
public ObservableCollection<ItemViewModel> Items { get { return items; } }
which is populated from code.
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Test.Commands;
namespace Test.ViewModels {
public class ItemViewModel : DependencyObject {
private ICommand toggleCommand;
public ItemViewModel(string title) {
Text = title;
Image = new BitmapImage(new Uri("graphics/someimage.png", UriKind.Relative));
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ItemViewModel), new PropertyMetadata(default(string)));
public static readonly DependencyProperty IsSelectedProperty =
DependencyProperty.Register("IsSelected", typeof(bool), typeof(ItemViewModel), new PropertyMetadata(default(bool)));
public static readonly DependencyProperty ImageProperty =
DependencyProperty.Register("Image", typeof(ImageSource), typeof(ItemViewModel), new PropertyMetadata(default(ImageSource)));
public string Text {
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public bool IsSelected {
get { return (bool)GetValue(IsSelectedProperty); }
set { SetValue(IsSelectedProperty, value); }
}
public ImageSource Image {
get { return (ImageSource)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
public ICommand ToggleSelected {
get { return toggleCommand ?? (toggleCommand = new RelayCommand(o => IsSelected = !IsSelected)); }
}
}
}
where RelayCommand is similar to the one found at WPF Apps With The Model-View-ViewModel Design Pattern article. The main difference is that CommandManager is not available in the Windows Phone SDK.
By using this model you can tap on rows to select them, using the ToggleSelected command in the view model, and deselect them by tapping them again, in effect showing or hiding the image.
I have a .wav music file.
When I tried to play using SoundEffect.Play();
mus1.Play(); I am getting noise rather than music.
The same is played well in PCs music player.
How to resolve this issue?
How to make sure that it will play good in Windows Phone 7 too?
It sounds like there's content in the .wav file that WP7 doesn't understand. Why don't you try converting it to .wav (yes I know it's already in .wav) as this may remove the unknown data.
Audacity (http://audacity.sourceforge.net/) is free and will do this for you. Just drag the .wav file into it and click file --> export...
Try the following Code
MainPage.xaml.cs
namespace MediaSample
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
progress.DataContext = this;
this.Loaded += new System.Windows.RoutedEventHandler(MainPage_Loaded);
mediaplayer.BufferingProgressChanged += new System.Windows.RoutedEventHandler(mediaplayer_BufferingProgressChanged);
mediaplayer.CurrentStateChanged += new RoutedEventHandler(mediaplayer_CurrentStateChanged);
}
public double Duration { get; set; }
void mediaplayer_CurrentStateChanged(object sender, RoutedEventArgs e)
{
if (mediaplayer.CurrentState == MediaElementState.Playing)
{
Duration = mediaplayer.NaturalDuration.TimeSpan.TotalSeconds;
ThreadPool.QueueUserWorkItem(o =>
{
while (true)
{
Dispatcher.BeginInvoke(new Action(() => Progress = mediaplayer.Position.TotalSeconds * 100 / Duration));
Thread.Sleep(0);
}
});
}
}
void mediaplayer_BufferingProgressChanged(object sender, System.Windows.RoutedEventArgs e)
{
MediaElement mediaplayer = sender as MediaElement;
if (mediaplayer.BufferingProgress == 1)
Debug.WriteLine(mediaplayer.NaturalDuration);
}
void MainPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
mediaplayer.Source = new Uri("/Oru nalum..mp3", UriKind.Relative);
mediaplayer.Play();
}
public double Progress
{
get { return (double)GetValue(ProgressProperty); }
set { SetValue(ProgressProperty, value); }
}
// Using a DependencyProperty as the backing store for Progress. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ProgressProperty =
DependencyProperty.Register("Progress", typeof(double), typeof(PhoneApplicationPage), new PropertyMetadata(0.0));
}
}
MainPage.xaml
<phone:PhoneApplicationPage
x:Class="MediaSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="Media Application" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<MediaElement x:Name="mediaplayer"/>
<ProgressBar Height="40" x:Name="progress" Value="{Binding Path=Progress}"/>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
Add Mp3 file as follows,
Like that you can add .wav files. Working good. Tested codes above.
Thank you.
Use MeadiaElement Rather than using SoundEffect Class.
try this one
MediaElement
I'd like to change Foreground color of TextBlock (bellow TitleText and DateText) in DataTemplate from code.
<ListBox x:Name="listBox1" ItemsSource="{Binding}" ScrollViewer.ManipulationMode="Control" SelectionChanged="listBox1_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="stackPanel1" HorizontalAlignment="Stretch" Orientation="Horizontal">
<TextBlock FontSize="35" x:Name="TitleText" Text="{Binding Title}" Width="386" Foreground="Black" />
<TextBlock FontSize="25" x:Name="DateText" Text="{Binding Date}" Width="78" Foreground="Black" />
<TextBlock x:Name="Id" Text="{Binding Id}" Visibility="Collapsed" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'd like to do like this in code behind. But It seems not be able to access x:Name property in DataTemplate.
this.TitleText.Foreground = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0);
Does anyone know a good solution for this ?
Why don't you do it the Fast way instead of crawling the Visual Tree.
<TextBlock FontSize="35" Text="{Binding Title}" Width="386" Foreground="[Binding Color}" />
Then all you have to do is:
Add a Color Brush Property in your Collection
Change this property to the color you want
Make sure this property implement INotify or is a Dependency Property
Example
XAML
<Grid>
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Stretch" Orientation="Horizontal">
<TextBlock Text="{Binding Title}" Foreground="{Binding TitleColor}" />
<TextBlock Text="{Binding Date}" Foreground="Black" />
<TextBlock Text="{Binding Id}" Visibility="Collapsed" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
CodeBehind
public partial class MainPage : Page
{
public ObservableCollection<TEST> TestCollection { get; private set; }
public MainWindow()
{
InitializeComponent();
TestCollection = new ObservableCollection<TEST>();
TestCollection.Add(new TEST()
{
TitleColor = Brushes.Black,
ID = 0,
Title = "A",
Date = DateTime.Now,
});
TestCollection.Add(new TEST()
{
TitleColor = Brushes.Red,
ID = 1,
Title = "B",
Date = DateTime.Now.AddDays(1),
});
DataContext = TestCollection;
}
}
public class TEST : INotifyPropertyChanged
{
private Brush _TitleColor;
public Brush TitleColor
{
get
{
return _TitleColor;
}
set
{
_TitleColor = value;
OnPropertyChanged("TitleColor");
}
}
private int _ID;
public int ID
{
get
{
return _ID;
}
set
{
_ID = value;
OnPropertyChanged("ID");
}
}
private string _Title;
public string Title
{
get
{
return _Title;
}
set
{
_Title = value;
OnPropertyChanged("Title");
}
}
private DateTime _Date;
public DateTime Date
{
get
{
return _Date;
}
set
{
_Date = value;
OnPropertyChanged("Date");
}
}
public TEST()
{
}
#region INotifyProperty
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
#endregion
}
You can use FindItem method to find element in visual tree by it name and then change it Foregorund.
((listBox.ItemContainerGenerator.ContainerFromIndex(5) as FrameworkElement).FindName("TitleText") as TextBlock).Foreground = new SolidColorBrush(Color.FromArgb(255, 128, 128, 128));
where 5 is your item index
To Expand on MyKuLLSKI's answer, if your change is based on some value already in your object (eg. an int property that is greater than 5), you could use a ValueConverter (see here for an example) to read the value and return a brush. That is cleaner than adding a colour to your model since it is (arguably) UI related rather than data related.
MyKuLLSKI gave me perfect solution. But I couldn't make it.
I was struggling and I found my problem. I wrote the answer (only for me ) in my blog. Please take a glance it.
Cannot bind two types of data source to one UI target
http://myprogrammingdial.blogspot.com/2012/03/cannot-bind-two-types-of-data-source-to.html