Creating Silverlight Overlay User Control - c#

I'm creating a silverlight user control that will display a transparent overlay with text over whatever xaml is contained if a property is set to true. So for example:
<my:Overlay Message="You don't have access to this feature." ShowOverlay="{Binding IsFeatureAvailable}">
<TextBox />
<Button Content="Search" />
</my:Overlay>
What I'm not quite sure about is how to implement the ability to put arbitrary xaml inside my user control, like above.
Thanks for any help.

Inherit your OverlayControl from ContentControl. Your template would look something like:
<Grid>
<Grid x:Name="Overlay" Background="#30000000">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
<TextBlock Text="{TemplateBinding Message}"/>
</Grid>

This should work
<Grid>
<my:Overlay Message="You don't have access to this feature." ShowOverlay="{Binding IsFeatureAvailable}"/>
<TextBox />
<Button Content="Search" />
</Grid>
Also you can derrive you Overly control from ContentControl, and put content and OverLay layer in grid like shown above

Related

WPF C# - TextBlock inside custom ProgressBar not showing [duplicate]

This may be a no-brainer for the WPF cognoscenti, but I'd like to know if there's a simple way to put text on the WPF ProgressBar. To me, an empty progress bar looks naked. That's screen real estate that could carry a message about what is in progress, or even just add numbers to the representation. Now, WPF is all about containers and extensions and I'm slowly wrapping my mind around that, but since I don't see a "Text" or "Content" property, I'm thinking I'm going to have to add something to the container that is my progress bar. Is there a technique or two out there that is more natural than my original WinForms impulses will be? What's the best, most WPF-natural way to add text to that progress bar?
Both of the prior responses (creating a new CustomControl or an Adorner) are better practices, but if you just want quick and dirty (or to understand visually how to do it) then this code would work:
<Grid Width="300" Height="50">
<ProgressBar Value="50" />
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
My Text
</TextBlock>
</Grid>
Just keep in mind that the z-index is such that the last item listed will be on top.
Also, if you don't have Kaxaml yet, be sure to pick it up - it is great for playing with XAML when you're trying to figure things out.
This can be very simple (unless there are alot of ways getting this to work).
You could use Style to get this done or you just overlay a TextBlock and a ProgressBar.
I personally use this to show the percentage of the progress when waiting for completion.
To keep it very simple I only wanted to have one Binding only,
so I attached the TextBock.Text to the ProgressBar.Value.
Then just copy the Code to get it done.
<Grid>
<ProgressBar Minimum="0"
Maximum="100"
Value="{Binding InsertBindingHere}"
Name="pbStatus" />
<TextBlock Text="{Binding ElementName=pbStatus, Path=Value, StringFormat={}{0:0}%}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
Here is how this could look like:
Check out WPF Tutorial for the full post.
If you are needing to have a reusable method for adding text, you can create a new Style/ControlTemplate that has an additional TextBlock to display the text. You can hijack the TextSearch.Text attached property to set the text on a progress bar.
If it doesn't need to be reusable, simply put the progress bar in a Grid and add a TextBlock to the grid. Since WPF can compose elements together, this will work nicely.
If you want, you can create a UserControl that exposes the ProgressBar and TextBlock as public properties, so it would be less work than creating a custom ControlTemplate.
You could use an Adorner to display text over top of it.
See MSDN article on Adorners
You would create a class that inherits from the Adorner class. Override the OnRender method to draw the text that you want. If you want you could create a dependency property for your custom Adorner that contains the text that you want to display. Then use the example in the link I mentioned to add this Adorner to your progress bar's adorner layer.
ProgressBar with Text and Binding from 2 Properties ( Value/Maximum value ):
<Grid>
<ProgressBar Name="pbUsrLvl"
Minimum="1"
Maximum="99"
Value="59"
Margin="5"
Height="24" Foreground="#FF62FF7F"/>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock.Text>
<MultiBinding StringFormat="{}UserLvl:{0}/{1}">
<Binding Path="Value" ElementName="pbUsrLvl" />
<Binding Path="Maximum" ElementName="pbUsrLvl" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
Rezult:
The same but with % of progress :
<Grid>
<ProgressBar Name="pbLifePassed"
Minimum="0"
Value="59"
Maximum="100"
Margin="5" Height="24" Foreground="#FF62FF7F"/>
<TextBlock Text="{Binding ElementName=pbLifePassed, Path=Value, StringFormat={}{0:0}%}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
Right click ProgressBar, and click Edit Template > Edit a Copy.
Then put the TextBlock as shown below just above the closing tag of Grid in the Style generated by VS.
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"/>
<TextBlock Background="Transparent" Text="work in progress" Foreground="Black" TextAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
This is based on the given answers.
Since I´m using MahApps Metro, I ended up with this:
<Grid>
<metro:MetroProgressBar x:Name="pbar" Value="50" Height="20"></metro:MetroProgressBar>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding ElementName=pbar, Path=Value, StringFormat={}{0:0}%}"></TextBlock>
</Grid>
If you want to use the normal bar with Metro Style:
<Grid>
<ProgressBar x:Name="pbar" Value="50" Height="20" Style="{StaticResource MetroProgressBar}"></ProgressBar>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding ElementName=pbar, Path=Value, StringFormat={}{0:0}%}"></TextBlock>
</Grid>
Same without Style:
<Grid>
<ProgressBar x:Name="pbar" Value="60" Height="20" Style="{x:Null}"></ProgressBar>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding ElementName=pbar, Path=Value, StringFormat={}{0:0}%}"></TextBlock>
</Grid>
What is Happening?
You have your progressbar and simply just lay text over it.
So you just use your progressbar as you would.
Put the progressbar in a grid and lay an textblock in it.
Then you can text as you wish or grab the current percenteage wich is the value from the progressbar.

WPF SettingsDialog using a ListView's SelectedItem and a ContentPresenter

I thought I cooked up something rather brilliant, but it's not working (yet!).
I am trying to get rid of all code behind in a SettingsDialog where a SettingsGroup can be selected by the user, which will consequently be visualized to the right of ListView (a similar settings dialog as Visual Studio has).
I was tipped to use a ContentPresenter, which I did, but then later realized that the tipper probably meant to rely on only XAML to get the job done.
This is what I got so far.
Declaring the SettingsGroups in XAML:
<Grid.Resources>
<w:DefinePathsUserControl x:Key="DefinePathSettingsGroup"></w:DefinePathsUserControl>
<w:HideShowTvShowsUserControl x:Key="HideShowTvShowsSettingsGroup"></w:HideShowTvShowsUserControl>
</Grid.Resources>
Add the left hand side SettingsGroup selector (a simple ListView):
<ListView
x:Name="SettingsGroupSelector"
Grid.Row="0"
Grid.Column="0">
<ListViewItem
x:Name="PathSetting"
Tag="{StaticResource DefinePathSettings}"
Content="Path"/>
<ListViewItem
x:Name="HideShowTvShowsSetting"
Tag="{StaticResource HideShowTvShowsSettings}"
Content="Hide/Show TV Shows"/>
</ListView>
And then I thought I could simply bind the ContentPresenter to the tag of the selected item in the ListView, like:
<ContentPresenter
x:Name="SettingsContentPanel"
Grid.Row="0"
Grid.Column="2"
Grid.ColumnSpan="2"
Content="{Binding Source=SettingsGroupSelector, Path=SelectedItem.Tag}" />
Unfortunately for me, this does not show anything in my ContentPresenter. I also don't get any errors in my output window.
Who can help me further?
Change
<ContentPresenter
x:Name="SettingsContentPanel"
Grid.Row="0"
Grid.Column="2"
Grid.ColumnSpan="2"
Content="{Binding Source=SettingsGroupSelector, Path=SelectedItem.Tag}" />
to this
<ContentPresenter
x:Name="SettingsContentPanel"
Grid.Row="0"
Grid.Column="2"
Grid.ColumnSpan="2"
Content="{Binding ElementName=SettingsGroupSelector, Path=SelectedItem.Tag}" />
More information on specifying the Binding Source

WPF custom control - reach element inside, rotate only part of custom control

I have a problem with custom control.
I have a custom controls, where i have 5-8 Paths, what user can "select". Up of those Paths i want to have label (inside custom control), where i can change the content inside (from Window, where i use that custom control).
My XAML of the Custom control looks like:
<FirstMolarTooth ..........>
<DockPanel>
<Label Name="lbl_tooth" DockPanel.Dock="Top" FontSize="10" HorizontalAlignment="Center" />
<Grid DockPanel.Dock="Bottom" HorizontalAlignment="Center">
<Path ......./>
</Grid>
</DockPanel>
</FirstMolarTooth>
How can i reach that label inside from window where i use that custom control??
something like:
<local:FirstMolarTooth x:Name="Tooth_15" ........>
<lbl_tooth Content="15" />
</local:FirstMolarTooth>
or
<local:FirstMolarTooth .... Content="15">
</local:FirstMolarTooth>
Second problem is that i rotate the custom control in window where i use it with:
<local:FirstMolarTooth ....>
<local:FirstMolarTooth.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="180"/>
</local:FirstMolarTooth.LayoutTransform>
</local:FirstMolarTooth>
My problem is that when i do that (logically), this rotate whole control (with a label). I want to rotate just the Paths and not with the label. I thought that i can do something like custom property for that label "isRotated" and when its setted on true, i should "reset" the rotate (set angle 0) with triggers. But i am not able to do that. (should i reach that custom property from XAML? or only in code? that was maybe the problem i try to reach it from XAML).
I know i can delete the label from custom control and have in there just the Paths and after that rotate just the Paths and the label have in Window. But user can select "whole" custom control (select tooth) and he can select "segment" of tooth (Paths). Therefore i would like to have it everything inside that custom control.
Thanks for any advice.
For your first problem, just bind lbl_tooth against FirstMolarTooth Content property. If that doesn't work, create new dependency property inside FirstMolarTooth(of string) and bind against it. Then you can change that property later outside of custo control.
<FirstMolarTooth x:Name="MOLAR" ..........>
<DockPanel>
<Label Name="lbl_tooth" DockPanel.Dock="Top" FontSize="10" HorizontalAlignment="Center"
Content="{Binding Content, ElementName=MOLAR}" />
<Grid DockPanel.Dock="Bottom" HorizontalAlignment="Center">
<Path ......./>
</Grid>
</DockPanel>
For the second problem, just make new dependency property of type DOUBULE that you can set outside. For creating dependency properties, you can either google or search this forum. Millions of answers.
<FirstMolarTooth x:Name="MOLAR" ..........>
<DockPanel>
<Label Name="lbl_tooth" DockPanel.Dock="Top" FontSize="10" HorizontalAlignment="Center"
Content="{Binding Content, ElementName=MOLAR}" />
<Grid DockPanel.Dock="Bottom" HorizontalAlignment="Center">
<Path .......>
<Path.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5"
Angle="{Binding YourNewAngleProperty, ElementName=MOLAR}"/>
</Path.LayoutTransform>
</Path>
</Grid>
</DockPanel>

How do you add items to a Canvas that is part of a UserControl?

I have a usercontrol that contains 2 rows. 1st row has a label and 2nd row has a scrollviewer with a canvas:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="TITLE" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" Name="label1" VerticalAlignment="Top" FontSize="26" />
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<Canvas Background="White" />
</ScrollViewer>
</Grid>
In my main window.xaml I'm trying to add this user control and then add items to it's canvas.
<local:UserCanvas>
<label Content="Test" />
</local:UserCancas>
There problem here is that when I had that label in there it just overrides the "TITLE" label in row 1 of the user control. How do I add things so that they are placed on the cavas of the UserControl?
Instead of defining the Content in your UserControl, define the UserControl.ContentTemplate
For example, instead of writing
<UserControl ...>
<Grid>
...
<Canvas />
...
</Grid>
</UserControl>
use
<UserControl ...>
<UserControl.ContentTemplate>
<DataTemplate>
<Grid>
...
<Canvas>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Canvas>
...
</Grid>
</DataTemplate>
</UserControl.ContentTemplate>
</UserControl>
If you use the first syntax, then specifying the Content when you use your UserControl will result in the existing Content getting overwritten, so your rendered Visual Tree ends up looking like this:
<local:UserCanvas>
<label Content="Test" />
</local:UserCancas>
By using the 2nd syntax, you're wrapping the Content in your ContentTemplate, so the rendered Visual Tree ends up looking like this:
<local:UserCanvas>
<Grid>
...
<Canvas>
<label Content="Test" />
</Canvas>
...
</Grid>
</local:UserCanvas>
I would try adding a public property (that you check and respond to in the user control's Page_Load()) and/or public method (that you just call from outside the control) to the user control which you can then access from your main program. Which way to go depends a bit on how complicated the actions you're needing to take will be. It looks to me like this will be simple enough to handle through the public property + Page_Load() method.

Frame does not use Toolkit Transitions with ProgressBar inside Frame Template

I am switching to using a ProgressBar/Grid in the Frame of my application instead of via a Popup. I used this stack overflow post to get it working : Dynamic Progress bar In WP7
However, When using the example I no longer have page transitions. It will be hard for me to warrant the use of it if page transitions will not work properly. Is there something I'm missing? I tried setting the TargetType to "TransitionFrame", but that does not work properly and throws a XAML parse exception (for the namespace Microsoft.Phone.Controls.PhoneApplicationPages)
<ControlTemplate x:Key="LoadingIndicatorTemplate" TargetType="toolkit:TransitionFrame" >
<Grid x:Name="ClientArea">
<ContentPresenter />
<Grid x:Name="ProgressGrid" Background="Black" Opacity="0.85" Visibility="Collapsed" Loaded="ProgressGrid_Loaded">
<StackPanel x:Name="Loading" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10">
<TextBlock HorizontalAlignment="Center" Name="tbLoading" Text="Loading" Style="{StaticResource TextNormalStyle}" />
<ProgressBar Style="{StaticResource PerformanceProgressBar}" HorizontalAlignment="Center" Name="pbLoading" Width="400" Margin="10" IsIndeterminate="False" />
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
For using the Toolkit's TransitionFrame for page transitions as well as a custom ControlTemplate to show your progress bar, you must specify the TargetType for the ControlTemplate as toolkit:Transitionframe where toolkit is defined as:
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
The rest of the problem is that your ControlTemplate does not specify the template parts that the TransitionFrame requires. It requires two parts of type ContentPresenter named FirstContentPresenter and SecondContentPresenter. Change your ControlTemplate to the following to bring page transitions back:
<ControlTemplate x:Key="LoadingIndicatorTemplate" TargetType="toolkit:TransitionFrame">
<Grid x:Name="ClientArea">
<ContentPresenter x:Name="FirstContentPresenter" />
<ContentPresenter x:Name="SecondContentPresenter" />
<Grid x:Name="ProgressGrid"
Background="Black"
Opacity="0.85"
Visibility="Collapsed"
Loaded="ProgressGrid_Loaded">
<StackPanel x:Name="Loading"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="10">
<TextBlock x:Name="tbLoading"
HorizontalAlignment="Center"
Text="Loading"
Style="{StaticResource BoaTextNormalStyle}" />
<toolkit:PerformanceProgressBar x:Name="pbLoading"
HorizontalAlignment="Center"
Width="400"
Margin="10"
IsIndeterminate="False" />
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
NOTE: Jeff Wilcox's PerformanceProgressBar is now part of the Silverlight Toolkit, so you can use it directly as shown above.
If you're putting the progressbar on the frame but then animating the page then the animation won't include the progressbar.
Why not just put the progressbar on the page?

Categories