SizeToContent paints an unwanted border - c#

Whenever I try to make a window and I set the SizeToContent to WidthAndHeight, on opening the window correctly sizes to it's contents, but it adds a small border to the right and the bottom. On resizing this disappears, and when using a set height and width this problem also doesn't occur.
This is a sample of what I mean:
You could say this is not a huge problem, though I find it makes my application look unprofessional, especially when I need to present this. Does anybody know why this is happening, or whether there is a workaround? I am coding this project in C#.
XAML Code:
<Window x:Class="FPricing.InputDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="InputDialog" Width="400" Height="300" SizeToContent="WidthAndHeight">
<StackPanel>
<Label x:Name="question">?</Label>
<TextBox x:Name="response"></TextBox>
<Button Content="OK" IsDefault="True" Click="Button_Click" />
</StackPanel>
</Window>
Values are passed on on creation of the class.
However I experience this problem on every window I have ever created, even without custom underlying code.

<Window UseLayoutRounding="True" /> works for me.

Using this tool (it's good, btw) I found that the Border control of the Window (it's immediate child) doesn't fill the whole window, leaving that "border", which is actually the background of the Window control.
I've found a workaround. Width and Height of the Border are NaN. If you set those to an integer value, the "border" disappears.
Let's use the values of ActualWidth and ActualHeight, but rounded to an integer.
Define the converter:
C#
[ValueConversion(typeof(double), typeof(double))]
public class RoundConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return Math.Ceiling((double)value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
return value;
}
}
XAML (remember to include your namespace, in this case "c")
<c:RoundConverter x:Key="RoundConverter"/>
Then create a style binding the size to the actual size using the converter. It's important to use a Key, so it won't apply to every Border (most controls use it):
<Style TargetType="{x:Type Border}" x:Key="WindowBorder">
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={StaticResource RoundConverter}}"/>
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight, Converter={StaticResource RoundConverter}}"/>
</Style>
Finally, apply this style to the first child of the window (the Border control):
private void Window_Loaded(object sender, RoutedEventArgs e) {
GetVisualChild(0).SetValue(StyleProperty, Application.Current.Resources["WindowBorder"]);
}
If someone can do this in a simpler way, please share too.

managed to solve it, by combining Gabriel and smg answers.
Upon loading the window, get the border in question, and set its LayoutRounding to true.
this.Loaded += (sender, args) =>
{
var border = this.GetVisualChild(0) as Border;
if (border != null)
border.UseLayoutRounding = true;
};

Okay, heres a related answer in which you can refer to a great answer.
Automatic resizing when border content has changed
So basically you want to add something like this, but put it to the values that you want:
<Border x:Name="border"
BorderBrush="Cornsilk"
BorderThickness="1">
<Ellipse Width="40"
Height="20"
Fill="AliceBlue"
Stroke="Black" />
</Border>

Related

C# WPF math expressions on variables in XAML

I digged out the internet in order to find a solution, and didn't found any clear solution and none of them working.
I'm looking for a specific solution, but if someone here have better solution it will be great..
In general, I'm trying to make controls that based on the Width and Height of the monitor.
- The easy way is put values that matches with my monitor and change them from CodeBehind.
Here's how it going:
- Create two variables in XAML (let's say the type is Double)
- Create third variables also in XAML. His value will be the difference of the
other two variables (in absolute)
- Create 3 control, the width of those controls is the value of the variables
<Window xmlns:sys="clr-namespace:System;assembly=mscorlib >
<sys:Double x:Key="size1">290</sys:Double>
<sys:Double x:Key="size2">450</sys:Double>
<sys:Double x:Key="size3"> Maybe something here? </sys:Double>
<StackPanel>
<Button Name="Button1" Width="{Binding Source={StaticResource size3}}"
Height="50" />
</StackPanel>
</Window>
I'm new in WPF, I do know C# pretty well but XAML is new for me (few months).
Basically I want to know if its possible to use undefined variables, such as 10% of the screen width.
Thanks.
You can use a Converter to achieve that.
public class WidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value / 10;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
in Xaml
<StackPanel>
<StackPanel.Resources>
<local:WidthConverter x:Key="WidthConverter" />
</StackPanel.Resources>
<Button Name="Button1"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth, Converter={StaticResource WidthConverter}}"
Height="50" />
</StackPanel>

How to change color of all shapes in window with C# and XAML?

Brief
I am trying to programmatically change the colour of specific elements at runtime. The project currently uses Telerik and I am able to change the theme at runtime: This works as expected with no issues. I can't, however, figure out how to change the fill or stroke colour at runtime of custom shape elements in XAML.
Within my project I have a ResourceDictionary file named _Icons.xaml that contains vector shapes to use as the content for other controls (such as buttons).
Code
App.xaml.cs
I am using the following code to change the theme's marker colours at runtime.
GreenPalette.Palette.MarkerColor = (Color)ColorConverter.ConvertFromString("#FF000000");
_Icons.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyNamespace">
<ControlTemplate x:Key="Box">
<Viewbox>
<Rectangle Width="357" Height="357" Fill="#000000"/>
</Viewbox>
</ControlTemplate>
<ControlTemplate x:Key="BoxOutline">
<Viewbox>
<Rectangle Width="357" Height="357" StrokeThickness="45" Stroke="#000000"/>
</Viewbox>
</ControlTemplate>
</ResourceDictionary>
MainWindow.xaml
<telerik:RadButton>
<StackPanel>
<ContentControl Template="{StaticResource Box}" Height="58"/>
<TextBlock HorizontalAlignment="Center" Margin="0,5,0,0">Box</TextBlock>
</StackPanel>
</telerik:RadButton>
<telerik:RadButton>
<StackPanel>
<ContentControl Template="{StaticResource BoxOutline}" Height="58"/>
<TextBlock HorizontalAlignment="Center" Margin="0,5,0,0">BoxOutline</TextBlock>
</StackPanel>
</telerik:RadButton>
Question
In _Icons.xaml I have the following lines:
<Rectangle Width="357" Height="357" Fill="#000000"/>
<Rectangle Width="357" Height="357" StrokeThickness="45" Stroke="#000000"/>
Given the following line in App.xaml.cs:
GreenPalette.Palette.MarkerColor = (Color)ColorConverter.ConvertFromString("#FF000000");
How can I either...
Programmatically change the values of Fill and/or Stroke (an element that only has Fill set should only change the Fill value and not add a Stroke attribute) from the App.xaml.cs file? Or ...
Bind the values in XAML for Fill or Stroke to receive the value given by my App.xaml.cs file?
Thank you for taking the time to read my question. Any help regarding this is greatly appreciated.
First i advise you to eject that controls off your resource sheet so you can actually control them properly.
When you do that, go the code behind your control and just use dependency property of type 'Color' of the 'SolidColorBrush' that is used by the background and then bind it by element name, you gotta build the project at least once before attempting to bind.
Here is how you write a dependency property
hint: in VS write 'propdp' and hit tab twice to bring up a template, but you can use mine for now.
public Color _color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register("_color", typeof(Color), typeof(Fileentity), null);
after you build once go to the xalm and put this inside your rectangle:
<Grid.Background>
<SolidColorBrush Color="{Binding
_color,ElementName=YourControlName" />
</Grid.Background>
if you do it right you will be able to access this property when inserting the control on you Page like
<local:YourcontrolName _color="{x:Bind MyColorProperty }"/>
where 'MyColorProperty' is a property that implements INotifyPropertyChanged.
An alternative way is to use a datacontext directly on the usercontrol and just bind your color to one of its properties like:
public YourControl(){
this.InitializeComponent();
this.DataContext = new MyClassDataContext();
var myContext= (MyClassDataContext)this.DataContext;
_color=MyContext.MyColorProperty;}
Where MyClassDataContext is any given class that contains a Color property(MyColorProperty) of your choosing.
You need a Dependency property here as well that binds to your Controls xalm like i showed before.
I know all this is might too hard to grasp at once, thats cause it requires basic knowledge of MvvM.

Visual Studio WPF UI Designer with Custom Controls

This is a bit of a weird question:
I have a custom control that inherits from TextBox, and provides "ghost" text - eg it says "Username" in a box until you click inside it, whereupon the "ghost" text disappears, and the user can type in their, in this case, Username.
The "Ghost text" for a control is simply a property in a subclass of TextBox. I then set TextBox.Text to it whenever relevant.
In the Visual Studio WPF XAML preview window (the standard UI design one), I would like to be able to "preview" the "Ghost text" - like when you set the actual text of a textbox, you can see it in the preview, not just when you run the application.
I have tried setting the Text property to the relevant Ghost text in the OnInitialised function, but it doesn't have any effect on the preview.
Where should I be putting code that affects the preview of a control in the designer?
Bonus question: Is there an actual name for what I call "ghost" textboxes? Would be good to know for the future!
Is there an actual name for what I call "ghost" textboxes? Would be god to know for the future!
I have seen this referred to as a "hint" when describing its purpose, or as a "watermark" when describing its appearance. I tend to employ the former, as it describes the function, which is more in line with the WPF design philosophy: the actual presentation is determined by the template, and the conceptual "hint" could be presented differently simply by applying a custom style/template. Why imply that it should be a watermark when someone could choose to present it in another way?
Design-wise, I think you're approaching this the wrong way. I would implement this such a way that controls other than a TextBox could more easily opt in: use attached properties.
I would create a static class, say HintProperties, which declares a couple of attached dependency properties:
Hint - declares the hint content; typically a string, but it need not be. It could simply be an object, akin to the Content property of a ContentControl.
HasHint - a computed, read-only bool property that gets reevaluated when Hint changes, and simply indicates whether a control has a Hint specified. Useful as a Trigger condition to toggle the visibility of a hint presenter in your control template.
Then, provide a custom style for your TextBox (or other control) which overlays a Hint presenter atop the regular content, hidden by default. Add a trigger to reduce the opacity of the hint when the control has keyboard focus, and another to make the hint Visible when Text is an empty string.
If you really want to go all-out, you can throw in HintTemplate and HintTemplateSelector properties.
However, if this seems like overkill, you can simply declare a Hint or Watermark property directly on your derived TextBox class. I would not try to implement this by conditionally changing the Text property, as that would interfere with data binding and, potentially, value precedence.
You can do this in a reusable way using a style which you would typically declare in your App.xaml. In this style you replace the control template with your own implementation and wrap together some controls. Basically you make up the WatermarkTextBox from a normal TextBox with a transparent background and place a TextBlock control with standard text behind the TextBox. The Visibility of this TextBlock is bound to the TextBox using a specific TextInputToVisibilityConverter so it will disappear when the TextBox has text or just has the focus.
While this maybe looks like a lot of code, you define this once and you can reuse this whereever you need, just by setting style of the TextBox
Declaration of some resources
xmlns:c="clr-namespace:YourNameSpace.Converters"
<SolidColorBrush x:Key="brushWatermarkBackground" Color="White" />
<SolidColorBrush x:Key="brushWatermarkForeground" Color="LightSteelBlue" />
<c:TextInputToVisibilityConverter x:Key="TextInputToVisibilityConverter" />
Declaration of the style:
<Style x:Key="SearchTextBox" TargetType="{x:Type TextBox}">
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid Background="{StaticResource brushWatermarkBackground}">
<TextBlock Margin="5,5" Text="Search..."
Foreground="{StaticResource brushWatermarkForeground}" >
<TextBlock.Visibility>
<MultiBinding
Converter="{StaticResource TextInputToVisibilityConverter}">
<Binding RelativeSource="{RelativeSource
Mode=FindAncestor, AncestorType=TextBox}"
Path="Text.IsEmpty" />
<Binding RelativeSource="{RelativeSource
Mode=FindAncestor, AncestorType=TextBox}"
Path="IsFocused" />
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
<Border x:Name="Border" Background="Transparent"
BorderBrush="{DynamicResource SolidBorderBrush}"
BorderThickness="1" Padding="2" CornerRadius="2">
<!-- The implementation places the Content into the
ScrollViewer. It must be named PART_ContentHost
for the control to function -->
<ScrollViewer Margin="0" x:Name="PART_ContentHost"
Style="{DynamicResource SimpleScrollViewer}"
Background="Transparent"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The implementation of the TextInputToVisibilityConverter, which just takes text input, converts to bool and converts this to Visibility. Also keeps Focus into account.
namespace YourNameSpace
{
public class TextInputToVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values,
Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (values[0] is bool && values[1] is bool)
{
bool hasText = !(bool)values[0];
bool hasFocus = (bool)values[1];
if (hasFocus || hasText)
return Visibility.Collapsed;
}
return Visibility.Visible;
}
public object[] ConvertBack(object value,
Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Now all infrastructure is into place. In your view/usercontrol/window just alter the style of the Textbox and there it is, your watermark textbox..
<TextBox Style="{DynamicResource SearchTextBox}" />

Blend switch between 2 visual states (WP7.1)

I think what I am doing is fairly simple, I guess I am just missing something.
I have a StackPanel inside another StackPanel. What I want to do is to hide / show the inner one when the outter one is clicked.
I have 2 states in blend. First makes a StackPanel Collapsed, the other one Expanded.
I added 2 behaviours (GoToStateBaheviour) to the outter StackPanel and assigned their triggers to MouseLeftButtonDown event. In the first behaviour in Conditions I check whether the the inner StackPanel is collapsed, if it is it switches to the state Expanded.
The other behaviour works vice versa - in Conditions I check whether the the inner StackPanel is visible, if it is it switches to the state Collapsed.
Now both of these Behaviours individualy work just fine. But combined, not a chance. I tried to change the Event name of one of them to "ManipulationDelta" and then both started working - but to activate the one I have to try to drag it.
Seems like having 2 behaviours attached to the same event is causing a trouble. What would you recommend?
EDIT
I uploaded the entire solution so you can open it in Blend
http://leteckaposta.cz/800017526
(The project is for WPF as opposed to the one I have for WP7, but that shouldnt matter)
I changed the behaviour to ChangePropertyAction, which should make it easier to read. There are two of them - both react to MouseLeftButtonDown with a Condition for Visibility property. one of them changes it to Visible, the other one to Collapsed.
But only one of them works. I suspect it is always the "upper one" (the one that comes first). Feel free to test it out yourselves
CODE
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
x:Class="WpfApplication1.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<StackPanel Height="168" Width="305" HorizontalAlignment="Left" VerticalAlignment="Top" Background="#FF7C7070">
<TextBlock Height="59" TextWrapping="Wrap" Text="Outter">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:Interaction.Behaviors>
<ei:ConditionBehavior>
<ei:ConditionalExpression>
<ei:ComparisonCondition LeftOperand="{Binding Visibility, ElementName=stackPanel}" Operator="Equal">
<ei:ComparisonCondition.RightOperand>
<Visibility>Visible</Visibility>
</ei:ComparisonCondition.RightOperand>
</ei:ComparisonCondition>
</ei:ConditionalExpression>
</ei:ConditionBehavior>
</i:Interaction.Behaviors>
<ei:ChangePropertyAction TargetObject="{Binding ElementName=stackPanel}" PropertyName="Visibility">
<ei:ChangePropertyAction.Value>
<Visibility>Collapsed</Visibility>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:Interaction.Behaviors>
<ei:ConditionBehavior>
<ei:ConditionalExpression>
<ei:ComparisonCondition LeftOperand="{Binding Visibility, ElementName=stackPanel}" Operator="NotEqual">
<ei:ComparisonCondition.RightOperand>
<Visibility>Visible</Visibility>
</ei:ComparisonCondition.RightOperand>
</ei:ComparisonCondition>
</ei:ConditionalExpression>
</ei:ConditionBehavior>
</i:Interaction.Behaviors>
<ei:ChangePropertyAction TargetObject="{Binding ElementName=stackPanel}" PropertyName="Visibility">
<ei:ChangePropertyAction.Value>
<Visibility>Visible</Visibility>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
<StackPanel x:Name="stackPanel" Height="106" RenderTransformOrigin="0.489,-0.842" Background="#FF708B7C" Visibility="Hidden">
<TextBlock Height="50" Margin="74,0,65,0" TextWrapping="Wrap" Text="Inner"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
As you've commented in Chris W.'s answer, when you place both triggers in the same event, they compete against each other and cancel each other out. You can verify this by using a MouseLeftButtonUp on one of the triggers.
A simple code behind event can resolve this issue.
XAML
<Grid x:Name="LayoutRoot">
<StackPanel Background="Red" MouseLeftButtonDown="OnMouseLeftButtonDown">
<TextBlock FontSize="22" Text="Outter" />
<StackPanel x:Name="stackPanel"
Height="75"
Background="Yellow">
<TextBlock FontSize="22" Text="Inner" />
</StackPanel>
</StackPanel>
</Grid>
Code Behind
private void OnMouseLeftButtonDown( object sender, MouseButtonEventArgs e )
{
stackPanel.Visibility = stackPanel.Visibility == Visibility.Visible
? Visibility.Collapsed
: Visibility.Visible;
e.Handled = true;
}
What is happening is that your triggers are firing sequentially and not simultaneously. Here is what is happening,
MouseLeftButtonDown event fired
First trigger activates, checks the Visibility, it is Visible so it changes it to Collapsed
Second trigger activates, checks the Visibility it is Collapsed so it changes it to Visible
The net result is that it is stuck in the Visible state. You can verify this by changing the order of the Triggers - the result will be stuck in the Collapsed state.
One way around this that does not require code-behind for each instance is to use a Converter which 'flips' Visible to Collapsed. you can then use a ChangePropertyAction to set a value which is determined via a Binding through this converter, e.g.
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<ec:ChangePropertyAction
TargetName="stackPanel"
PropertyName="Visibility"
Value="{Binding Visibility,
Converter={StaticResource VisibilityToOpposite},
ElementName=stackPanel}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
The Converter looks like this,
public class VisibilityToOpposite : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
Visibility vis = (Visibility)value;
return (vis == Visibility.Collapsed) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
throw new NotImplementedException();
}
}
The great thing about this method is that the Converter can be reused and also is not limited to two states e.g.
public class StringToNextString : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
string s = (string)value;
List<string> allStrings = (parameter as string).Split(new char[] { '|' }).ToList();
// Find the index of the next string along
int i = allStrings.IndexOf(s);
i = (i + 1) % allStrings.Count;
return allStrings[i];
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
throw new NotImplementedException();
}
}
and then call with a ConverterParameter of pipe delimited strings to cycle through e.g.
Value="{Binding Text, ConverterParameter=one|two|three,
Converter={StaticResource StringToNextString},
ElementName=stackPanel}"

Ribbon ApplicationMenu AuxilaryPane Size

How do I change the size of the AuxilaryPane in the WPF Ribbon ApplicationMenu? I have added a recent file list to that area but it is getting truncated. Ideally I'd like the auxilary pane to fill the screen like it does for Word/Excel.
My code:
<r:Ribbon.ApplicationMenu>
<r:RibbonApplicationMenu>
<r:RibbonApplicationMenu.AuxiliaryPaneContent>
<StackPanel>
<TextBlock Text="Recent Files" />
<Separator />
<ItemsControl ItemsSource="{Binding RecentFiles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<r:RibbonApplicationMenuItem Header="{Binding ShortPath}"
Command="{Binding DataContext.OpenRecentFileCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding LongPath}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</r:RibbonApplicationMenu.AuxiliaryPaneContent>
</r:RibbonApplicationMenu>
</r:Ribbon.ApplicationMenu>
Based on the answers in this thread I found it easiest to subclass RibbonApplicationMenu and set Width of the third column to Auto.
public class CustomRibbonApplicationMenu : System.Windows.Controls.Ribbon.RibbonApplicationMenu
{
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
System.Windows.DependencyObject obj = this.GetTemplateChild("PART_AuxiliaryPaneContentPresenter");
System.Windows.Controls.ContentPresenter c = obj as System.Windows.Controls.ContentPresenter;
((System.Windows.Controls.Grid)((System.Windows.Controls.Border)c.Parent).Parent).ColumnDefinitions[2].Width = System.Windows.GridLength.Auto;
}
}
Now you just need to change your Ribbon xaml from
<Ribbon.ApplicationMenu>
<RibbonApplicationMenu>
to
<Ribbon.ApplicationMenu>
<ctrl:CustomRibbonApplicationMenu>
If you are looking for a very quick fix to increase the height, you can simply add some useless RibbonApplicationMenuItems to pad out the box (and not have to modify MS source code).
<ribbon:Ribbon.ApplicationMenu>
<ribbon:RibbonApplicationMenu>
<ribbon:RibbonApplicationMenu.Items>
<ribbon:RibbonApplicationMenuItem Name="saveSettings" Header="Save Settings" />
<ribbon:RibbonApplicationMenuItem IsEnabled="False"/> <!--USELESS-->
<ribbon:RibbonApplicationMenuItem IsEnabled="False"/> <!--USELESS-->
</ribbon:RibbonApplicationMenu.Items>
<ribbon:RibbonApplicationMenu.AuxiliaryPaneContent >
<StackPanel Orientation="Vertical" >
<GroupBox>
<Label Content="System Settings" />
</GroupBox>
<StackPanel Orientation="Horizontal">
</StackPanel>
</StackPanel>
</ribbon:RibbonApplicationMenu.AuxiliaryPaneContent>
</ribbon:RibbonApplicationMenu>
</ribbon:Ribbon.ApplicationMenu>
I've searched a solution for the same problem.
There is no direct property to modify this.
An Example of creating such property can be found at
msdn
here's the main solution:
Change the source code of the Ribbon Library. MS has provided the source code of the Ribbon Library: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=2bfc3187-74aa-4154-a670-76ef8bc2a0b4
Download the source code and open it, in the MicrosoftRibbonForWPFSourceAndSamples\RibbonControlsLibrary\Microsoft\Windows\Controls\Ribbon\RibbonApplicationMenu.cs, add one Dependency Property:
public double MinMenuHeight
{
get { return (double)GetValue(MinMenuHeightProperty); }
set { SetValue(MinMenuHeightProperty, value); }
}
public static readonly DependencyProperty MinMenuHeightProperty =
DependencyProperty.Register("MinMenuHeight", typeof(double), typeof(RibbonApplicationMenu), new UIPropertyMetadata(0.0));
In the MicrosoftRibbonForWPFSourceAndSamples\RibbonControlsLibrary\Themes\Generic.xaml, line 7519, add the XAML code:
<Border x:Name="PopupBorder" MinHeight="{TemplateBinding MinMenuHeight}" BorderBrush="{Binding RelativeSource={RelativeSource AncestorType={x:Type ribbon:RibbonMenuButton}}, Path=Ribbon.BorderBrush}" Background="{Binding RelativeSource={RelativeSource AncestorType={x:Type ribbon:RibbonMenuButton}}, Path=Ribbon.Background}" BorderThickness="1" CornerRadius="2">
<Grid>
</Grid>
</Border>
Only add the first two rows of the given xaml
This is an old thread, yes, and it has some good ideas, but I wasn't satisfied.
My problem was slightly different in that I needed the ApplicationMenu to expand only enough to fit any control that was placed in the auxiliary pane.
Eventually I dug deep and found a solution I was happy with. It doesn't solve the "fill the screen" problem, but I'm hoping this will help others who land here, looking for a solution to a problem similar to mine. Sorry if it looks like I'm trying to hijack the thread. I don't intend to.
Essentially I solved the fixed width and height problem by changing the ribbon style:
Open the ribbon assembly in JetBrains DotPeek
Open Resources/System.Windows.Controls.Ribbon.g.resources/Themes/generic.baml
Copy the entire resource dictionary into a .xaml file in your project. You may be able to get away with using only a part of it, but I decided to take the whole thing.
At this point you may be asking, "Why not just use VS or Blend or ShowMeTheTemplate instead of DotPeek?" All of these tools failed miserably on the ribbon assembly. Don't know why. They didn't say. One of the problems with using DotPeek is that some of the namespace references will need adjusting, but it's not too difficult, so I won't go into details here.
So, now that you have all the styles and templates, go look for the offending markup.
First, fix the width:
Look for the grid whose third column definition is a static value of 300. You can search for <ColumnDefinition Width="300"/>. There is only one.
Change the "300" to "Auto".
Then fix the height:
Look for the definition of PART_SubmenuPlaceholder Border. You can search for x:Name="PART_SubmenuPlaceholder". It is about 50 lines below the change you did for the width.
That Border binds the Height property to the ActualHeight property of the "MainPaneBorder" control: Height="{Binding ElementName=MainPaneBorder, Path=ActualHeight}".
Remove this Height definition.
Now that you've modified the style, just add this resource dictionary to your xaml and it should apply itself to the ribbon.
When I came across this answer (while searching for an answer to my own, slightly different question), I wasn't too excited about actually modifying Microsoft code.
As a result, I rather preferred to subclass it, and get the hold of the necessary UI element using base.GetTemplateChild on the relevant "PART_...".
I suppose you can follow a similar approach to achieve what you need.
My example is here.
Hope this helps.
P.S. If you happen to find a way to determine the necessary width of the AuxiliaryPanel, please let me know - I would like to see if that's applicable to the menu's width as well.
You can download the Microsoft Ribbon for WPF Source Code (http://www.microsoft.com/en-us/download/details.aspx?id=11877) and add a DependencyProperty Width/Height to ApplicationMenu or just do it 'quick and dirty' like in my example:
MainWindow.xaml
public partial class MainWindow : RibbonWindow
{
private Size DefaultApplicationMenuSize;
public MainWindow()
{
InitializeComponent();
}
private void RibbonWindow_Loaded(object sender, RoutedEventArgs e)
{
var grid = (myRibbon.ApplicationMenu.Template.FindName("MainPaneBorder", myRibbon.ApplicationMenu) as Border).Parent as Grid;
/* before the first opening of the menu the size is NaN, so you have to measure size and use the DesiredSize */
grid.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
this.DefaultApplicationMenuSize = new Size(grid.ColumnDefinitions[2].Width.Value, grid.DesiredSize.Height);
}
private void RibbonApplicationMenuItem_MouseEnter(object sender, MouseEventArgs e)
{
Button b=new Button();
b.Content = "my epic button";
b.Width = 500;
b.Height = 500;
b.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
SetApplicationMenuSize(b.DesiredSize);
this.ribbonContentPresenter.Content = b;
}
private void RibbonApplicationMenuItem_MouseLeave(object sender, MouseEventArgs e)
{
SetApplicationMenuSize(DefaultApplicationMenuSize);
this.ribbonContentPresenter.Content = null;
}
private void SetApplicationMenuSize(Size size)
{
var grid = (myRibbon.ApplicationMenu.Template.FindName("MainPaneBorder", myRibbon.ApplicationMenu) as Border).Parent as Grid;
/* you can modify the width of the whole menu */
//grid.Width = size.Width;
/* or just the size of RibbonApplicationMenu.AuxiliaryPaneContent */
grid.ColumnDefinitions[2].Width = new GridLength(size.Width);
grid.Height = size.Height;
}
}
MainWindow.xaml.cs
<ribbon:RibbonWindow x:Class="WpfRibbonApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
Title="MainWindow"
x:Name="RibbonWindow"
Width="640" Height="480"
Loaded="RibbonWindow_Loaded">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ribbon:Ribbon x:Name="myRibbon">
<ribbon:Ribbon.ApplicationMenu>
<ribbon:RibbonApplicationMenu SmallImageSource="Images\SmallIcon.png">
<ribbon:RibbonApplicationMenuItem Header="Hello _Ribbon"
ImageSource="Images\LargeIcon.png"/>
<ribbon:RibbonApplicationMenuItem Header="HoverTest"
ImageSource="Images\LargeIcon.png"
MouseEnter="RibbonApplicationMenuItem_MouseEnter"
MouseLeave="RibbonApplicationMenuItem_MouseLeave"
StaysOpenOnClick="True" />
<ribbon:RibbonApplicationMenu.FooterPaneContent>
<ribbon:RibbonButton Label="What ever" HorizontalAlignment="Right"/>
</ribbon:RibbonApplicationMenu.FooterPaneContent>
<ribbon:RibbonApplicationMenu.AuxiliaryPaneContent>
<ribbon:RibbonContentPresenter Name="ribbonContentPresenter" />
</ribbon:RibbonApplicationMenu.AuxiliaryPaneContent>
</ribbon:RibbonApplicationMenu>
</ribbon:Ribbon.ApplicationMenu>
</ribbon:Ribbon>
</Grid>
</ribbon:RibbonWindow>
have a nice day

Categories