VisualBrush using MediaElement in a Style - wpf

I have a UserControl that converts a text to a shape. I can then Stroke it or Fill it with a Brush. When I try to use a Visual Brush with a MediaElement (video) as the Source I am running into problems. When I do it directly in the XAML as below:
<custom:ExtendedTextBlock Text="Video Filled Text" FontFamily="Arial Black" FontSize="60">
<custom:ExtendedTextBlock.Fill>
<VisualBrush>
<VisualBrush.Visual>
<MediaElement Source="assets\1267066.mp4" Width="596" Height="366" LoadedBehavior="Play" Stretch="UniformToFill" MediaEnded="MediaElement_MediaEnded" MediaFailed="MediaElement_MediaFailed" MediaOpened="MediaElement_MediaOpened" />
</VisualBrush.Visual>
</VisualBrush>
</custom:ExtendedTextBlock.Fill>
</custom:ExtendedTextBlock>
It works great. The problem appears when I try to create a Style using the same information:
<Style x:Key="VideoFill" TargetType="{x:Type custom:ExtendedTextBlock}">
<Setter Property="StrokeThickness" Value="2" />
<Setter Property="Stroke" Value="Black" />
<Setter Property="Fill">
<Setter.Value>
<VisualBrush>
<VisualBrush.Visual>
<MediaElement Source="assets/1267066.mp4" Width="596" Height="366" LoadedBehavior="Play" LoadedBehavior="Play" Stretch="UniformToFill" MediaEnded="MediaElement_MediaEnded" MediaFailed="MediaElement_MediaFailed" MediaOpened="MediaElement_MediaOpened" />
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</Style>
I get no fill. No MediaOpened is thrown, no MediaFailed is thrown. It just doesn't render the fill. Using this same method with a SolidColorBrush, LinearGradientBrush, ImageBrush all works perfectly. Can anyone tell me what is going on here?

I've seen all sorts of examples of MediaElement not playing nicely with other WPF components, I don't think the dev team did their integration testing quite as comprehensively with that one as perhaps they did with other things. This particular case appears to be a bug I've seen crop up a few times where an element used in a style is created and then destroyed several times during initialization. MediaElement seems to be doing some type of deferred processing, gets confused and winds up thinking that it's no longer being used. The solution, believe it or not, is to simply set UnloadedBehavior="Play" as well.
Personally though I tend to avoid letting the XAML framework control things like this. My own approach with MediaPlayer is to make each instance a static resource, set both LoadedBehavior and UnloadedBehavior to "Manual" and control playback manually with a Blend behavior containing dependency properties that I bind back to my view models. This provides all the advantages of complete code-driven control of the media element without breaking MVVM and without having to cross your fingers and hope that the framework behaves itself.

Related

Styling a control template in Silverlight 5

I'm looking at using the Silverlight Menu Control from Codeplex. It's functionally very good but I'd like to restyle the appearance. Is it possible to do this without just making a new copy of the template and changing a few properties? Here's an example from the generic "theme" that comes with the control:
<Style TargetType="GenericControl:MenuBar">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GenericControl:MenuBar">
<Canvas x:Name="LayoutRootMB">
<StackPanel Height="25"
x:Name="baseRectMB"
Canvas.Left="0"
Canvas.Top="0"
HorizontalAlignment="Left"
Orientation="Horizontal" />
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'd like to change, say, HorizontalAlignment to Stretch (for the sake of argument -- never mind if it'll actually accomplish anything useful). Is there any way to tell XAML (in XAML, not in C#) that I want to do something to baseRectMB?
baseRectMB is named in a TemplatePartAttribute on class MenuBar.
I assume I can simply copy the existing template and alter it, though I haven't gotten that working yet either.

WPF comboBox Arrow Button

I'm doing a wpf project and inside my application i have a combobox.Can i know any simple way to change the dropDown arrow color? I found the resource here, but its too complicate. Anyone can help me out?
p/s: i'm a newbie
combobox example:
Because the arrow is just linked to a system resource, I believe there's no way to change it other than redoing the entire template like you see in your linked article. It seems complicated, but it's not so bad, especially if you have Blend (just because Blend makes it easy to pull out the current template to edit it).
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Path x:Name="Arrow" Fill="White"/>
</ControlTemplate>
</Setter.Value>
</Setter>

Style to choose suitable foreground according to background color

I have a WPF application which ships with a set of default styles for Label, TextBox etc. defined by item types (no explicit keys defined).
Within the application there are two main containers used, one with dark background and one with light background, such that sometimes it's right to use black as the foreground color for a Label and sometimes its dramatically wrong. On the other hand, editors are always styled rather traditionally with light background and dark foreground, so I cannot just set the foreground for all child elements to the inverse.
Is there an elegant way to make my labels (and maybe TextBlocks as well) to decide about their foreground color dependent on 'their' background? I only want to switch between two colors, thus no auto-contrast-maximization needed, only some threshold to avoid white font on white ground.
I also don't want to define two sets of default styles, I strongly search for some way to make my single Label-Default-Style be appropriate for both background variants.
Is it possible (and feasible without too much performance hit) to add a trigger/binding to the style, which evaluates the current background color?
Alternatively, I would be interested in best practices how to cleanly set background-colors for certain FrameworkElements, especially containers/panels, without running into the problems described above.
Here is what I tried (simplified of course):
<UniformGrid>
<UniformGrid.Resources>
<!-- SimpleStyles: Label -->
<Style x:Key="{x:Type Label}" TargetType="{x:Type Label}">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Background" Value="Black">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UniformGrid.Resources>
<Label x:Name="bgSetExplicitly" Background="Black">abc
</Label>
<Border Background="Black">
<Label x:Name="bgInheritedFromParent" >abc
</Label>
</Border>
<Label>abc
</Label>
<Label>abc
</Label>
You can see that the label's background is chosen nicely, if the Label has an explicit background set (x:Name=bgSetExplicitly), but if the background is 'inherited' from the parent in the VisualTree (x:Name="bgInheritedFromParent"), it's not.
I would love to have that working that the style can evaluate the "effective background" (no matter where it comes from) and choose an appropriate foreeground-brush for this background.
This question seems to imply a deeper issue. I would guess that you haven't consolidated the management of foreground colors, and so you have an application that has code or styles that set foreground colors all over the place. And now you're dealing with one of the implications of that.
I'd face the deeper issue and fix that. I don't really understand why you're resistant to the idea of creating default styles, but assuming for the moment that you have a good reason not to do this (other than "I should have created default styles at some point, but now that I haven't and my application has gotten big, it's just too hard," in which case, I have a different suggestion), how about creating global resources?
Create objects in the application's resource dictionary for the controls' foreground and background colors, and fix the XAML so that instead of referencing brushes directly, it uses the DynamicResource markup extension to get them from the resource dictionary. In code, instead of setting the Foreground property on the controls to a brush directly, use GetResource to get the brush. And set the background the same way.
Once you've done this, if you want to change foreground/background colors globally in your application, you just change the resources.
This is basically how you start making a WPF application skinnable, which seems to be the road you're going down.
The easiest thing to do is bind the foreground color of your TextBoxes, etc. to the background of their containing element, and use a value converter to make the change. This is especially easy if you are only ever using two colors.
As an example....
public class ColorSwapper : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value == null) { return DependencyProperty.UnsetValue; }
Color srcColor = (value as SolidColorBrush).Color;
if (srcColor == Colors.Black)
{
return new SolidColorBrush(Colors.White);
}
else
{
return new SolidColorBrush(Colors.Black);
}
}
...
And some example XAML....
<Grid Grid.Column="1" Name="RightGrid" Background="White">
<TextBlock Text="Hello Nurse!" Foreground="{Binding ElementName=RightGrid, Path=Background, Converter={StaticResource ColorSwapper}}"/>
</Grid>
Of course you will probably want to make some tweaks and cleanup according to your specific needs, but that will do it.
Here is another possible approach. If your application only has ALL dark/light backgrounds and their compliments, you can try an approach like this, using the 'ColorSwapper' that I mentioned in my other answer.
<Window>
<Window.Resources>
<local:ColorSwapper x:Key="swapper"/>
<SolidColorBrush x:Key="BackBrush" Color="Black"/>
<!--<SolidColorBrush x:Key="BackBrush" Color="White"/>-->
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="{Binding Source={StaticResource BackBrush}, Converter={StaticResource swapper}}"/>
</Style>
</Window.Resources>
<Grid Background="{StaticResource BackBrush}">
<TextBlock FontSize="24" FontWeight="Bold">ABC</TextBlock>
</Grid>
</Window>
Now whenever you change the color value of 'BackBrush', all of the related foreground colors will automatically update. Based on your discussions, I think that this will also meet your style requirements. At any rate, you will likely have to make small mods to ensure that this approach will fit your exact scenario.

WPF Toolkit Chart - Collapsing Chart Points

I have a chart with 1000s of points of data and am wondering how to remove the data points? They slow the whole process down considerably. I researched about having to change the style, is there another way?
Removing (collapsing) DataPoints in a LineSeries?
<Grid>
<chartingToolkit:Chart
Width="Auto" Height="Auto"
Background="Transparent" Panel.ZIndex="3">
<chartingToolkit:LineSeries Title="Symbol" Background="Transparent"
IndependentValueBinding="{Binding Path=Key}"
DependentValueBinding="{Binding Path=Value}"
ItemsSource="{Binding Path=SymbolData}"
DataContext="{Binding}">
<chartingToolkit:LineSeries.DataPointStyle>
<Style TargetType="{x:Type chartingToolkit:LineDataPoint}">
<Setter Property="Background" Value="Red"/>
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</chartingToolkit:LineSeries.DataPointStyle>
</chartingToolkit:LineSeries>
</chartingToolkit:Chart>
</Grid>
I thought the code above would've worked, but apparently not...
Further research, even this answer did not work : /
Removing markers from silverlight line or area series
Cheers for the help.
Setting the point styles to Collapsed won't solve your issue as the objects will still be in the visual tree affecting rendering time. Since you have set up bindings for the data points, the only way to remove them is to remove your business objects that they are bound to.
Also, since you're talking about performance, it's worth noting that the WPF toolkit's performance is much worse than some other free charting components. See this article on charting component's performance comparison - it was written comparing Silverlight versions, but according to my experience it holds for WPF as well. Using Visiblox, DD3 or Visifire would probably significantly improve the performance of your charts. (Full disclosure: I have been involved in developing in Visiblox)

How to display a MessageBox when wrong input is given and reverting the old value of TextBox using MVVM in WPF

I have been using WPF and its built in validation controls for quiet sometime. I was going through an excellent article in codeproject whose link is given below
http://www.codeproject.com/KB/WPF/wpfvalidation.aspx
I am having a requirement from one of our clients which I have not been able to chieve using MVVM in WPF.
The problem is as follows :
There is a TextBox which accepts only numbers.
When the user enters any value other than numbers I have to display an error to him. The error should
highlight the TextBox, provide a ToolTip
display an error in MessageBox
revert the TextBox to its previous value
For example when the TextBox is loaded, it might have an initial value say 10
. Then the user enters some wrong value say "aa".
Now I have to display a MessageBox saying "Wrong value" and then revert the value back to 10.
There are lot of articles and ways to display error in WPF say by using ErrorTemplate and so on.
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right"
Foreground="Orange"
FontSize="12pt">
!!!!
</TextBlock>
<Border BorderBrush="Green" BorderThickness="1">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
But how do I revert the value and display a MessageBox. I know it can be displayed using an event in code-behind file but I dont want to write any logic in my code behind file. I want to achieve this functionality using MVVM
A sample illustration will be really helpful!!
the answer to your 2nd question: build a messageboxservice and just call it from your viewmodel. you can find mvvm messageboxservices in all wpf frameworks. look at cinch for example.
the undo redo thing, hmm its built in in wpf, so strg+z will work. but i dont know yet how to get it work with mvvm :)
Hey people finally I solved the problem. Its based on this
StackOverFLow Solution
The solution is very simple. I call the Validator on losing focus from TextBox. The validator return me a Validation Result.Based on the result I can take some action.
I used attached behaviour for this. I have written a trigger which checks if Validation.HasError is true or not. If it is true, then it assigns some dummy value to my attached property. While assigning I will have TextBoxBase under my control. Using this I just call the Undo() function and it solves my problem.

Resources