How to use content of derived controls in silverlight - silverlight

In my project lots of views must have Ok,Cancel button to bottom of view. So i want create a base control. And add Ok, Cancel button to bottom of this control. Then i will inherite this control. In the inherited control i want to ad a textbox to near this buttons. How can i do this?

I believe there is a template for the base control.Is so in the inherited control's template edit the button panel and add textbox.

You can create Control which is inherited from ContentControl and define your buttons in ControlTemplate of it. Then you can just use this control as shown in sample.
ControlWithButtons.cs
[TemplatePart(Name="btnOk", Type= typeof(Button))]
public class ControlWithButtons : ContentControl
{
public ControlWithButtons()
{
this.DefaultStyleKey = typeof(ControlWithButtons);
}
Button _btnOk;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_btnOk = GetTemplateChild("btnOk") as Button;
if (_btnOk != null)
{
// do what you want with you button
_btnOk.Click += new RoutedEventHandler(_btnOk_Click);
}
}
void _btnOk_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Ok button clicked");
}
}
Generic.xaml (must be in (ProjectDir)/Themes/Generic.xaml)
(do not forget xmlns:local="clr-namespace:Test")
<Style TargetType="local:ControlWithButtons">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ControlWithButtons">
<Border Background="Yellow" CornerRadius="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Border Margin="10" Background="LightGray">
<ContentPresenter/>
</Border>
<Button Grid.Row="1" x:Name="btnOk" Content="OK" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Using your control:
<Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<local:ControlWithButtons Width="300" Height="250" HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- TextBox is put into control -->
<TextBox Width="200" Height="Auto" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5" />
<!-- You can also specify ContentTemplate for ControlWithButtons -->
<!-- (see in MSDN "http://msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol.contenttemplate(v=vs.95).aspx") -->
</local:ControlWithButtons>
</Grid>

I found the solution. [ContentProperty("")] attribute solved my problem.
Like this:
Base Xaml
<Grid Name="layoutRoot" VerticalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="289*" />
<RowDefinition Height="51" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Orientation="Horizontal">
<Button Name="btnOk" Content="Ok" Height="23" Width="75" HorizontalAlignment="Left" Margin="10,10,10,10" Command="{Binding Path=OnApply, Mode=OneWay}"/>
<Button Name="btnCancel" Content="Cancel" Height="23" Width="75" HorizontalAlignment="Left" Margin="10,10,10,10"/>
</StackPanel>
<Grid Name="rootContent" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Column="0" Grid.Row="0" />
</Grid>
</sdk:ChildWindow>
Base CodeBehind
[ContentProperty("RootContentControl")]//This attribute solved my problem.
public partial class BaseView : ChildWindow
{
public BaseView()
{
InitializeComponent();
}
public UIElementCollection RootContentControl
{
get { return rootContent.Children; }
}
}
Inherited Xaml
<Views:BaseView x:Class="MvvmLight1.Views.InheritedView"
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:Views="clr-namespace:MvvmLight1.Views"
xmlns:viewModels="clr-namespace:MvvmLight1.ViewModel"
mc:Ignorable="d" d:DesignHeight="244" d:DesignWidth="392"
DataContext="{Binding Source=viewModels:InheritedViewModel}">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
</Grid>
</Views:BaseView>
Inherited CodeBehind
public partial class InheritedView : BaseView
{
public InheritedView()
{
InitializeComponent();
}
}

Related

WPF WindowChrome unwanted black shadow - Caused by SizeToContent="WidthAndHeight"

I'm trying to create a custom popup window in WPF, but I can't seem to do it without a there being a black "drop shadow" around it. I'm using ContentControl for the body of it so that I can change the body for different popups.
I can remove the "shadow" by removing SizeToContent="WidthAndHeight", but then I don't have a window that adapts to it's content.
Here's the xaml
<Window x:Class="PriceFinding.Utility.Dialogs.Service.DialogWindow"
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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PriceFinding.Utility.Dialogs.Service"
mc:Ignorable="d"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterScreen"
MinHeight="300" MinWidth="800"
Background="{StaticResource BrushPrimary}"
>
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="50"/>
</WindowChrome.WindowChrome>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" WindowChrome.IsHitTestVisibleInChrome="True" VerticalAlignment="Top" Background="{StaticResource BrushPrimaryDark}" Name="TitleBar" Height="35">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Image Source = "pf.ico" Height="20" Width="20" Margin="5,0" />
<Label Content="{Binding Title}" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="14"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,5,0">
<Button
x:Name="MinButton"
Height="35" Width="35" Padding="0"
Command="{Binding MinimizeButton.MinimizeCommand}">
</Button>
<Button
x:Name="MaxButton"
Height="35" Width="35" Padding="0"
HorizontalAlignment="Left"
Command="{Binding MaximizeButton.MaximizeCommand}">
</Button>
<Button
x:Name="CloseButton"
Height="35" Width="35" Padding="0"
HorizontalAlignment="Right"
Command="{Binding CloseButton.CloseCommand}">
</Button>
</StackPanel>
</Grid>
<ContentControl Grid.Row="1" x:Name="ContentPresenter" Content="{Binding}"></ContentControl>
</Grid>
How can I get around this?
Here (or here, for the more daring) is a workaround!
This is quite a weird problem, but, indeed, running an event when the content is rendered:
ContentRendered="Window_OnContentRendered"
like so:
private void Window_OnContentRendered(object sender, EventArgs e)
{
InvalidateVisual();
}
InvalidateVisual does not remeasure content of window. Also no need to change the chrome.
This helped me:
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
// Content of window may be black in case of SizeToContent is set.
// This eliminates the problem.
// Do not use InvalidateVisual because it may implicitly break your markup.
InvalidateMeasure();
}
You can set the GlassFrameThickness to zero:
<WindowChrome GlassFrameThickness="0"
CaptionHeight="0" />
And that should remove the drop shadow effect and it will also allow you to use the CornerRadius effect if you were interested.
This is caused by a bug in WPF.
See https://social.msdn.microsoft.com/Forums/vstudio/en-US/f51ba061-69e2-4c85-b77a-41307423c2bf/sizetocontentheight-windowstylenone-resizemodenoresize-weirdness?forum=wpf
For a workaround, you can refresh the view. InvalidateVisual did not work for me.
You can attach an event handler to the window like so:
Background="{StaticResource BrushPrimary}" Activated="Window_Activated" StateChanged="Window_Activated"
Then, in the code behind:
private void Window_Activated(object sender, EventArgs e)
{
this.SizeToContent = SizeToContent.Manual;
this.SizeToContent = SizeToContent.WidthAndHeight;
}

WPF Dependency Property Bound To User Control

I have a button subclass called MenuButton.
public class MenuButton : Button
{
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption", typeof(string), typeof(MenuButton), new UIPropertyMetadata(null));
public UserControl Icon
{
get { return (UserControl)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(UserControl), typeof(MenuButton),
new PropertyMetadata(null));
}
In the style I want to show an icon that was created using paths from SVG files. I have created a User Control containing the XAML for the icon:
<UserControl x:Class="WpfApplication1.Views.ScopeIcon"
.
.
.
>
<Viewbox Height="55"
Width="55">
<Grid>
<Path Fill="LightBlue" Data="M98.219,48.111C97..."/>
<Path Fill="LightBlue" Data="M98.219,46.948C97...."/>
</Grid>
</Viewbox>
</UserControl>
And here's the style:
<Style TargetType="Button"
x:Key="TestButtonStyle">
<Setter Property="Height" Value="140"/>
<Setter Property="Width" Value="195"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:MenuButton}">
<Border x:Name="TheBorder">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50*"/>
<RowDefinition Height="50*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Row="0"/> <===== THE USER CONTROL WILL GO HERE
<TextBlock Grid.Row="1"
Grid.Column="0"
Text="{TemplateBinding Caption}"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="5"
Foreground="White"
FontSize="14"
TextAlignment="Center"
TextWrapping="WrapWithOverflow"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I will set it here:
<ListBox Grid.Row="0"
ItemsSource="{Binding MainTools}" >
<ListBox.ItemTemplate>
<DataTemplate>
<controls:MenuButton Caption="{Binding Caption}"
Margin="2"
Width="100"
Style="{StaticResource TestButtonStyle}"
VerticalAlignment="Top"
Command="{Binding Path=ButtonClick}"
CommandParameter="{x:Static enums:Tabs.Oscilloscope}"
Icon=""/> <============= HOW DO I PUT THE SCOPEICON USER CONTROL HERE?
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm essentially trying to nest user controls, but I want to tell the button, in XAML, what UserControl to use for its icon.
Thank you
First, you need to update your style to set Content property on your ContentPresenter the same way you did for Text property on TextBlock.
<ContentPresenter Grid.Row="0" Content="{TemplateBinding Icon}"/>
And, then to set Icon on the MenuButton in your DataTemplate update your MenuButton element in DataTemplate to something like:
<controls:MenuButton Caption="Caption"
Margin="2"
Width="100"
Style="{StaticResource TestButtonStyle}"
VerticalAlignment="Top"
Command="{Binding Path=ButtonClick}"
CommandParameter="{x:Static enums:Tabs.Oscilloscope}">
<controls:MenuButton.Icon>
<views:ScopeIcon />
</controls:MenuButton.Icon>
</controls:MenuButton>

xaml window doesnt center

I have a xaml (window) control which contains a grid and inside that grid, two stackpanel. The second stackpanel is set to "collapsed" per visibility. When the form loads and the button on the form is clicked, the xaml window shows up centered by setting WindowStartupLocation="CenterScreen". But when the button on the xaml is clicked to set the second stackpanel's visibility to visible, it doesn't center no more. Can anyone help resolve this issue or tell me on how to fix this?
Update: After looking closely at this, I think it may be because the visibility is set to collapsed? I've tried instead of collapsed, hidden, and it centered it but with the column being shown empty as it's used by the stackpanel.
Here are the codes:
Form1.cs
public Form1()
{
InitializeComponent();
this.StartPosition = FormStartPosition.CenterScreen;
}
private void button_Click(object sender, EventArgs e)
{
MainWindow childWindow = new MainWindow();
childWindow.Show();
}
MainWindw.xaml
<Window x:Class="ChildProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:ChildProject"
Title="MainWindow"
Width="Auto"
Height="Auto"
SizeToContent="WidthAndHeight"
AllowsTransparency="False"
ResizeMode="NoResize"
WindowStyle="None"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<StackPanel x:Name="stkpnlMain"
Grid.Column="0"
Grid.Row="0"
Orientation="Vertical">
<Label Content="This is suppose to display message on right ..."
FontStyle="Italic"
FontWeight="Bold"/>
<Button Content="Click Me"
Width="75"
Margin="5" Click="Button_Click" />
</StackPanel>
<StackPanel x:Name="stkpnlDisplay"
Grid.Column="1"
Grid.Row="0"
Margin="5,0,0,0"
Orientation="Vertical"
Background="YellowGreen" Visibility="Collapsed" >
<Label Content="... First now shows ..."
BorderBrush="Black"
BorderThickness="1"
Background="Yellow" />
<Label Content="Hopefully this will work"
BorderBrush="Red"
BorderThickness="3"
Margin="0,5"
Background="White" />
</StackPanel>
</Grid>
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
stkpnlDisplay.Visibility = Visibility.Visible;
}

Sizing problems when using custom WPF dialog control

I am defining a custom control in WPF which serves as the base class for multiple dialog windows which all leverage shared services (positioning, Ok and Cancel buttons). The custom control is defined as follows:
public class ESDialogControl : Window
{
static ESDialogControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ESDialogControl), new FrameworkPropertyMetadata(typeof(ESDialogControl)));
}
internal ESDialogControl() { }
public ESDialogControl(string title)
{
Title = title;
this.KeyDown += new KeyEventHandler(ESDialogControl_KeyDown);
}
void ESDialogControl_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Escape: cancelButton_Click(null, null); break;
case Key.Enter: okButton_Click(null, null); break;
default: break;
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_okButton = base.GetTemplateChild("OkButton") as Button;
_okButton.IsEnabled = false;
_okButton.Click += new RoutedEventHandler(okButton_Click);
Button cancelButton = base.GetTemplateChild("CancelButton") as Button;
cancelButton.Click += new RoutedEventHandler(cancelButton_Click);
}
protected Button OkButton { get { return _okButton; } }
void cancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
void okButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
Close();
}
Button _okButton;
}
And the Generic.xaml which defines the template looks like this:
<Style TargetType="{x:Type local:ESDialogControl}">
<Setter Property="Width" Value="600" />
<Setter Property="Height" Value="Auto" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ESDialogControl}">
<Grid Height="Auto" Background="Beige" VerticalAlignment="Top" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="1" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}" />
<Rectangle Grid.Row="1" Fill="Navy" />
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="OkButton" Width="70" Margin="0 10 10 0">OK</Button>
<Button x:Name="CancelButton" Width="70" Padding="2" Margin="0 10 10 0">Cancel</Button>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Finally, I define my new dialog as a derived class:
<local:ESDialogControl x:Class="Mercersoft.Economica.Studio.View.DialogWindows.NewModelDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Mercersoft.Economica.Studio.View">
<Grid Background="Yellow" VerticalAlignment="Top" Height="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right">Name:</Label>
<TextBox x:Name="ItemName" x:FieldModifier="public" Grid.Column="1"
HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalContentAlignment="Center" TextAlignment="Left"
TextChanged="ItemName_TextChanged" />
<Label Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right">Description:</Label>
<TextBox x:Name="ItemDescription" x:FieldModifier="public" Grid.Row="1" Grid.Column="1"
AcceptsReturn="True" TextWrapping="Wrap" Height="140"
HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalContentAlignment="Center" TextAlignment="Left" />
</Grid>
</local:ESDialogControl>
Everything behaves as expected, except that the main window's height is way too large. It doesn't seem to fit just its content, but rather extends almost the entire height of the monitor. I went through the code to make sure VerticalAlignments are set to Top (rather than Stretch) and that the Height properties are set to Auto except for the description text box which has an explicit height.
Which property setting am I missing to get this custom control to size correct?
You are missing the SizeToContent="Height" setting in your ESDialogControl style. You can also take away the Height="Auto" setting, as that is the default for a Window.

Why do I have an Issue with binding to an image from a control template?

I have a style for an items control that binds to an image in the target, it only appears if the target also binds to the image and I have no idea why.. can anyone shed any light on it for me?
A simplified version of my style:
<Style x:Key="testStyle" TargetType="ItemsControl">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" LastChildFill="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" DockPanel.Dock="Top" MinHeight="25" SnapsToDevicePixels="True">
<StackPanel Orientation="Horizontal">
<Image Margin="10,0,10,0" VerticalAlignment="Stretch" Height="24" Width="24" Source="{Binding Path=HeaderImage}" />
<TextBlock FontFamily="Tahoma" VerticalAlignment="Center" Text="{Binding Path=HeaderInfo}" />
</StackPanel>
<Line VerticalAlignment="Bottom" Stretch="Fill"/>
</Grid>
<ItemsPresenter Grid.Row="1"/>
</Grid>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My User Control:
<UserControl x:Class="StartPageView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<ItemsControl Style="{DynamicResource testStyle}">
<Grid HorizontalAlignment="Stretch" >
<StackPanel>
<GroupBox Header="Information" Margin="0,0,0,10" >
<Label Margin="10,10,10,110">some useful information, dynamically updated</Label>
</GroupBox>
<GroupBox Header="Available actions" Margin="0,10,0,10">
<StackPanel>
<Label Margin="10,10,10,10">action 1</Label>
<Label Margin="10,10,10,10">action 2</Label>
<Label Margin="10,10,10,10">action 3</Label>
<!--<Image Width="0" Height="0" Source="{Binding HeaderImage}"/>-->
</StackPanel>
</GroupBox>
</StackPanel>
</Grid>
</ItemsControl>
And my model code (set as the data context for my user control)
internal class StartPageViewPresentationModel : IStartPageViewPresentationModel
{
public StartPageViewPresentationModel(IStartPageView view)
{
HeaderImage = new BitmapImage(new Uri(#"Images/home_16.png", UriKind.Relative)) { CacheOption = BitmapCacheOption.Default };
HeaderInfo = "Start Page";
View = view;
View.Model = this;
}
public BitmapImage HeaderImage { get; set; }
public string HeaderInfo { get; set; }
public IStartPageView View { get; set; }
}
If I un-comment the tag in the user control then the image is displayed both in the control and the template area, if I comment it it doesn't appear in either. The text binding from the template works fine
I am perplexed..
thanks
Trevor
Couple of suggestions:
Have you tried an absolute URI for the image?
HeaderImage can be of type ImageSource rather than the more restrictive BitmapImage.
I suspect what's happening is the UserControl is working because the path is relative and correct based on the location of the UserControl. The image is therefore cached and works from the template.
However, when you comment that out the image is resolved from the location of the Style, which may not be correct?

Resources