WPF Net Framework 3.5 Window Metro Style - wpf

I want to make Window with Metro style.
I found the 3 following libraries:
http://elysium.asvishnyakov.com/en/
https://github.com/MahApps/MahApps.Metro
http://mui.codeplex.com/
All are for Net Framework 4+.
Is there anything for 3.5?
I also tried to make it on my own (Didnt finish - still need to design it and add Resize [which I dont know how]) but I dont really like how it's made...:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" x:Class="Windows_Hider.MainWindow"
Title="Windows Hider" Height="350" Width="525" WindowStartupLocation="CenterScreen"
AllowsTransparency="True"
ResizeMode="CanResize" WindowStyle="None" BorderBrush="Black" BorderThickness="1" Icon="windowshider.ico">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image Width="24" Height="24" Source="{Binding Icon, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
<Label VerticalAlignment="Center" FontSize="14" Content="{Binding Title, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
</StackPanel>
<Grid MouseDown="Grid_MouseDown" Background="Transparent"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" Grid.Row="0">
<Button ToolTip="minimize" Background="White">
<Grid Width="30" Height="25">
<TextBlock Text="0" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="3.5,0,0,3" />
</Grid>
</Button>
<Grid Margin="1,0,1,0">
<Button x:Name="Restore" ToolTip="restore" Visibility="Collapsed">
<Grid Width="30" Height="25" UseLayoutRounding="True">
<TextBlock Text="2" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="2,0,0,1" />
</Grid>
</Button>
<Button x:Name="Maximize" ToolTip="maximize">
<Grid Width="31" Height="25">
<TextBlock Text="1" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="2,0,0,1" />
</Grid>
</Button>
</Grid>
<Button x:Name="Close" ToolTip="close">
<Grid Width="30" Height="25">
<TextBlock Text="r" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="0,0,0,1" />
</Grid>
</Button>
</StackPanel>
</Grid>
</Grid>
</Window>

Ok, it took me few days but in the end I managed to do something.
I had to make it by myself because there's no Metro Window for Net Framework 3.5.
I combined some of the references below:
Launch window's System Menu on custom window
http://www.codeproject.com/Articles/107994/Taskbar-with-Window-Maximized-and-WindowState-to-N
http://blog.magnusmontin.net/2013/03/16/how-to-create-a-custom-window-in-wpf/
http://codekong.wordpress.com/2010/11/10/custom-window-style-and-accounting-for-the-taskbar/
http://blog.creativeitp.com/posts-and-articles/c-sharp/simple-methods-to-drag-and-resize-your-c-transparent-wpf-application-with-the-windowstyle-property-set-to-none/
this is the final solution
Known problems / bugs:
1. When resizing the arrow cursor appear instead of the resizing cursor.
2. Designer cant display the custom window.
3. When maximizing, randomly there's blue (the color of the borders) in big area of the screen - for split second
If you can fix any of the problems above it will be even better but I am satisfied with what I achieved.
EDIT:
Updated to allow resize modes (also added sample)

It's relatively easy to do this yourself... all you need to do is copy the Style that you see in the Metro UI, as you call it. To start you off, here is a very simple Style that changes the ControlTemplate of the Button elements to remove their default look:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Of course, you'll want something to happen when the user moves their mouse pointer over the Button and you can do that by adding VisualStateManager.VisualStateGroups to the ControlTemplate. You can find a full example of this in the ControlTemplate Class page on MSDN.
The other controls Metro-style controls can be easily developed by creating simple ControlTemplates in the same way. Basically, you'll just need to remove the default WPF look and for the most part, just replace it with just a ContentPresenter as in the above example, or an ItemsPresenter for collection controls. Luckily the Metro look is very plain and simple, just remember to keep everything spaced out and plain.
To address another point you mad about resizing; you can set the Window.ResizeMode property to CanResizeWithGrip to add the resize grip in the bottom right corner of the Window as is often seen in these applications.

Related

WPF: Map UserControl properties to its children

The short version of my question is: Can properties of the UserControl be made available to the children of the UserControl without applying to the UserControl at the same time?
The long version: I am trying to create a "ButtonInput" which is a text box with a bitmap button at the right side, inside of the text box's border. This is pretty much how the search boxes look on many web sites (or in Visual Studio), with a magnifying glass at the right side.
The UserControl definition is:
<UserControl x:Class="Test.Controls.ButtonInput"
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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Test.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="Transparent">
<Border
Name="Border"
CornerRadius="6"
Padding="4"
Margin="2 2 2 2"
Background="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
BorderBrush="{Binding Path=BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
BorderThickness="1"
>
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="tbInput"
Grid.Column="0"
MaxLines="1"
Background="Transparent"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
Text="{Binding Path=Text, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
BorderThickness="0"/>
<Button Width="24" Grid.Column="1" Click="Button_Click">
<Button.Template>
<ControlTemplate>
<Image x:Name="imgIcon"
Source="{Binding Path=Source, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}" />
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</Border>
</Grid>
</UserControl>
I place this control in a test Window.
<Window x:Class="Test.TestWindow"
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:local="clr-namespace:Test"
xmlns:controls="clr-namespace:Test.Controls"
mc:Ignorable="d"
Title="TestWindow" Height="450" Width="800">
<Grid>
<StackPanel Orientation="Horizontal" Height="380" Width="402">
<Label Content="Password" Width="75" VerticalAlignment="Center"/>
<controls:ButtonInput x:Name="biTest" Source="Resources/img/password.png" Width="300" Height="35" Background="Orange" Foreground="Red" BorderBrush="Black" ButtonClick="ButtonInput_ButtonClick" />
</StackPanel>
</Grid>
</Window>
The problem I have is that I expect to have only what is inside the border colored orange, but instead the orange bleeds outside the border. I traced the problem to the way the Live Visual Tree looks like:
(ButtonInput)
(Border)
(ContentPresenter)
(Grid)
Border (Border)
(Grid)
tbInput (TextBox)
(Button)
The first Border is not in my control definition, but its background is Orange as inherited from the ButtonInput.
I did try an alternative: instead of using child controls for the content of the UserControl, I used a ControlTemplate with the same content. In this case, the executable looked OK (rounded rectangle with black border and orange background, no bleeding outside the border), but the designer in Visual Studio does not show anything. There is literally a blank space where the ButtonInput should be.
So, is there a way to prevent the properties set on the UserControl to apply to the first Border? Background is one example but there are other properties that I want to make use of the same way.
What's happening here is that your "ButtonInput" control isn't actually a button, it's a user control which just so happens to have a button on it. So when you set the background in the <controls:ButtonInput> tag on your main window you're effectively saying "ignore everything this user control says about the color of it's entire background because I'm now overriding it".
There are several ways around this, but the easiest one from the UserControl's perspective is to use the one last weapon in its arsenal: the template. Overriding the template in a control effectively says "I'm no longer going to be displayed the way a control of my type normally is, so all the usual settings won't apply unless I explicitly use them. That's as simple as doing this in your ButtonInput xaml:
<UserControl.Template>
<ControlTemplate>
<!-- all your old xaml code goes here -->
<Grid Background="Transparent">
<Border
Name="Border"
CornerRadius="6"
Padding="4"
<!-- etc -->
</ControlTemplate>
</UserControl.Template>
Which results in the following:
Truth be told, there are few cases in WPF where custom controls are actually needed, and this is almost certainly one of them. WPF is more than capable of supporting functionality like this with styles and templates alone. But this answer should suit your needs in the short term.
EDIT: If you want the control to be visible in the designer then populate it with a regular control and template that instead, it's what you probably should be doing anyway. Now your xaml should look like this:
<UserControl x:Class="WpfTestApp.Controls.ButtonInput"
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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfTestApp.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
x:Name="_this">
<UserControl.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Grid Background="Transparent">
<Border
Name="Border"
CornerRadius="6"
Padding="4"
Margin="2 2 2 2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1"
>
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="tbInput"
Grid.Column="0"
MaxLines="1"
Background="Transparent"
Text="{Binding ElementName=_this, Path=Text, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
Foreground="{TemplateBinding Foreground}"
BorderThickness="0" Margin="0,-1,0,1"/>
<Button Width="24" Grid.Column="1">
<Button.Template>
<ControlTemplate>
<Image x:Name="imgIcon" />
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<Button x:Name="biTest" Width="300" Height="35" Background="Orange" Foreground="Red" BorderBrush="Black" Template="{StaticResource ButtonTemplate}" />
</UserControl>
You haven't addressed the Text binding in your question, the code above is expecting a dependency property in the UserControl code behind:
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ButtonInput), new PropertyMetadata(String.Empty));
And you now use it like this:
<controls:ButtonInput x:Name="biTest" Width="300" Height="35" Text="{Binding MyText, Mode=TwoWay}" />

Event on ItemsControl issue [duplicate]

I`ve created big button which contains grid as below:
<Button Height="Auto" Width="Auto" Command="{Binding ContinueWithoutScan}" BorderThickness="0">
<Button.Template>
<ControlTemplate>
<Grid >
<TextBlock HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Text"
VerticalAlignment="Center" FontWeight="DemiBold"
Height="Auto" Width="Auto"
FontSize="25" Foreground="White"/>
<materialDesign:PackIcon Height="Auto" Width="70" Kind="ChevronRight" Foreground="White"
VerticalAlignment="Center" HorizontalAlignment="Right"/>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
There is problem that only TextBlock inside Template is clickable. Does anyone know how do I make whole content clickable? I working with MVVM so I dont want make Grid.OnMouseEneter.
Is there option to do that of I have to use EventTriggers?
The Grid needs to have a Background other than the default null to receive input events. You may set a transparent background instead of null:
<Grid Background="Transparent">
...
</Grid>

In Silverlight 4 , how does one add a cancel button to the BusyIndicator control?

I believe you can edit the template for the BusyIndicator, however, I do not have expression blend and I am not familiar with doing this. Does anyone have sample XAML that I could start with?
I presume blend just makes it easier to accomplish, but I am unsure how to begin with standard VS.NET.
There's no need to use Expression Blend - you can simply provide the control with a BusyContentTemplate. The Silverlight Toolkit examples demonstrate this here: http://www.silverlight.net/content/samples/sl4/toolkitcontrolsamples/run/default.html. Copying and pasting a snippet from those examples:
<controlsToolkit:BusyIndicator IsBusy="True" DisplayAfter="0">
<controlsToolkit:BusyIndicator.BusyContentTemplate>
<DataTemplate>
<StackPanel Margin="4">
<TextBlock Text="Downloading Email" FontWeight="Bold" HorizontalAlignment="Center"/>
<StackPanel Margin="4">
<TextBlock Text="Downloading message 4/10..."/>
<ProgressBar Value="40" Height="15"/>
</StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Pause" HorizontalAlignment="Right" Margin="0 0 2 0"/>
<Button Grid.Column="1" Content="Cancel" HorizontalAlignment="Left" Margin="2 0 0 0"/>
</Grid>
</StackPanel>
</DataTemplate>
</controlsToolkit:BusyIndicator.BusyContentTemplate>
</controlsToolkit:BusyIndicator>
Hope this helps...
Chris
This xaml addresses 2 issues that I had problems with by using the standard sample XAML (posted by Chris) from the Toolkit sources. I have also simplified the XAML to just add a Cancel button .
Data binding ( see here: http://forums.silverlight.net/forums/p/163280/368692.aspx )
Hiding the default progress bar, b/c once you use data template you should use your own progress bar, so you can control positioning
NOTE: I am using Caliburn Micro for MVVM, and if you're not using MVVM you'll probably just use a normal click event handler for the Cancel button.
Code sample:
<Controls:BusyIndicator IsBusy="{Binding IsBusy}" BusyContent="{Binding}">
<Controls:BusyIndicator.BusyContentTemplate>
<DataTemplate>
<StackPanel Margin="4">
<TextBlock Text="{Binding BusyContent}" FontWeight="Bold" HorizontalAlignment="Center" Margin="2"/>
<ProgressBar IsIndeterminate="True" Height="15" Margin="2"/>
<Button cal:Message.Attach="CancelBusyIndicator()" Content="Cancel" HorizontalAlignment="Right" Margin="2 2 2 2"/>
</StackPanel>
</DataTemplate>
</Controls:BusyIndicator.BusyContentTemplate>
<Controls:BusyIndicator.ProgressBarStyle>
<Style TargetType="ProgressBar">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</Controls:BusyIndicator.ProgressBarStyle>

Borderless ImageButtons in WrapPanel

I am attempting to create a WrapPanel with seamless ImageButtons containing Artwork. I put together the following ContentTemplate in the hopes that it would provide the seamless look required; however a thin white-line remained around each of the buttons. Can anyone steer me in the right direction?
<Button.ContentTemplate>
<DataTemplate DataType="{x:Type local:ArtInfo}">
<Border Name="border" BorderThickness="0" BorderBrush="blue" Height="280" Width="250" Background="#262c40">
<StackPanel>
<Grid>
<Grid.Resources>
<local:MyConverter x:Key="MyConverter"></local:MyConverter>
<ObjectDataProvider x:Key="Properties.Settings" ObjectType="{x:Type lcl:Properties.Settings}" />
</Grid.Resources>
<Image Name="ArtImage" Margin="10,15,0,0" Height="195" Width="195" VerticalAlignment="Top" >
<Image.Source>
<Binding Path="ArtImage"/>
</Image.Source>
</Image>
</Grid>
<TextBlock Text="{Binding Path=ArtClass}" Margin="10,-17,0,0" FontSize="11" Foreground="white" />
<TextBlock Text="{Binding Path=Student}" Margin="10,0,0,0" FontSize="11" Foreground="white" />
<TextBlock Text="1998" Margin="10,0,0,0" FontSize="11" Foreground="white" />
</StackPanel>
</Border>
</DataTemplate>
</Button.ContentTemplate>
The ContentTemplate tells WPF how to display the content within the Button -- the Button chrome (such as the border and background) remains, and the templated content is displayed within and over that chrome.
You want to replace the entire appearance of the Button, border and all, rather than just customising how its content is displayed. To do this, you need to use the Template property instead. The value of Button.Template is a ControlTemplate rather than a DataTemplate. Within that ControlTemplate, you can use the ContentPresenter to display the "data-templated" content.
In your case, since your DataTemplate is doing all the work, you could get away with a raw ContentPresenter as your template:
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter />
</ControlTemplate>
</Button.Template>
However, if all your buttons are using the same background, you could move this into the ControlTemplate:
<Button.Template>
<ControlTemplate TargetType="Button">
<Border BorderBrush="Blue" ...>
<ContentPresenter />
</Border>
</ControlTemplate>
</Button.Template>
You could then remove the Border from the DataTemplate. This would really only matter if you were planning to reuse the same Button.Template with other content templates and wanted to keep the appearance of the Button consistent across different kinds of content.
create a usercontrol, put the botton & image in a grid.
<Grid>
<Image Source="icon.png" Panel.ZIndex="1" />
<Button
Panel.ZIndex="2"
FocusVisualStyle="{x:Null}"
Background="Transparent"/>
</Grid>

Why does this WPF button stretch across the window?

The button below always expands to be as wide as the TextBlock. I've tried StackPanel, DockPanel, Width="Auto", etc.
How can I make the button expand to the size of its own text (as in HTML) and not to the size of text in its environement?
<DockPanel HorizontalAlignment="Left">
<Button x:Name="ButtonFavorite"
DockPanel.Dock="Top"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click">
</Button>
<TextBlock DockPanel.Dock="Top" Text="this is a long text which makes the button stretch across the window, if this text is just a couple words, the button will be smaller, and this drives me up the wall" Margin="10" TextWrapping="Wrap" />
</DockPanel>
ANSWER:
Thanks Greg, that did it. Here is the full XAML that works now, you can right-click the button to change its Content so see that the button expands and contracts appropriately.
<Window x:Class="Test3784234.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<DockPanel HorizontalAlignment="Left">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" >
<Button x:Name="ButtonFavorite"
Padding="5"
Cursor="Hand"
DockPanel.Dock="Top"
Content="Customers"
Margin="10"
Click="ButtonFavorite_Click">
<Button.ContextMenu>
<ContextMenu>
<MenuItem x:Name="menuItemReports" Header="Reports" Click="MenuItem_Click" />
<MenuItem x:Name="menuItemContracts" Header="Contracts" Click="MenuItem_Click"/>
<MenuItem x:Name="menuItemCustomers" Header="Customers" Click="MenuItem_Click" />
<MenuItem x:Name="menuItemDocumentation" Header="Documentation Creation Instructions" Click="MenuItem_Click" />
<MenuItem x:Name="menuItemEmail" Header="E-Mail" Click="MenuItem_Click" />
</ContextMenu>
</Button.ContextMenu>
</Button>
</StackPanel>
<TextBlock x:Name="TheMessage" DockPanel.Dock="Top" Text="Right-click the 'favorites' button to change its function." Margin="10" TextWrapping="Wrap"/>
</DockPanel>
</Window>
All you need to do is set the HorizontalAlignment property on your button. It defaults to stretch therefore filling the available space.
<Button x:Name="ButtonFavorite"
HorizontalAlignment="Left"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click">
Regarding your annoyance at the sizing of buttons, this is something that seems to be targeted at the designer in the designer/developer workflow, while you're clearly working on the developer portion. For the sake of development, I always apply a few styles in my App.xaml to ensure somewhat better button sizing. For example, in the application tag in your app.xaml file:
<Application.Resources>
<Style TargetType="Button">
<Setter Property="MinWidth" Value="60" />
<Setter Property="MinHeight" Value="23" />
<Setter Property="Margin" Value="3" />
</Style>
</Application.Resources>
Regarding your actual question:
The problem is that your DockPanel is stretching to the width of the text and the button will naturally expand to fill the available area. If you want the quick and dirty solution you can do something like:
<DockPanel HorizontalAlignment="Left">
<Button x:Name="ButtonFavorite"
DockPanel.Dock="Top"
Content="Customers"
Margin="10"
Width="Auto"
MaxWidth="100"
Click="ButtonFavorite_Click">
</Button>
</DockPanel>
Note the MaxWidth. If you want a more composable result, isolate your button in another panel. (I'm using a stackpanel because I believe someone else already used a grid in their example):
<DockPanel HorizontalAlignment="Left">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Button x:Name="ButtonFavorite"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click" />
</StackPanel>
<TextBlock DockPanel.Dock="Top" Text="this is a long text which makes the button stretch across the window, if this text is just a couple words, the button will be smaller, and this drives me up the wall" Margin="10" TextWrapping="Wrap" />
</DockPanel>
I like the StackPanel in this case because I find myself using it to create the horizontal "bar" of buttons along the bottom of a Form- err- Window in the right corner.
You could try isolating the button from the main panel by putting it in another panel.
<DockPanel HorizontalAlignment="Left">
<Grid DockPanel.Dock="Top">
<Button x:Name="ButtonFavorite"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click">
</Button>
</Grid>
<TextBlock DockPanel.Dock="Top" Text="this is a long text which makes the button stretch across the window, if this text is just a couple words, the button will be smaller, and this drives me up the wall" Margin="10" TextWrapping="Wrap" />
</DockPanel>
Can you place them in a two column Grid with the button spanning just one column and the text spanning two columns?
Here's an example using a Grid layout versus a DockPanel. The idea is to have 2 columns and 2 rows. Put the Button it a single cell and make that row/column pair auto-sizing. Then put the TextBox into the second row and have it span both of the columns. This will essentially make the top-right cell just filler space and will achieve the behavior you're looking for.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Button
x:Name="ButtonFavorite"
Grid.Column="0"
Grid.Row="0"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click">
</Button>
<TextBlock
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="1"
Margin="10"
TextWrapping="Wrap"
Text="this is a long text which makes the button stretch across the window, if this text is just a couple words, the button will be smaller, and this drives me up the wall" />
</Grid>
As another method to do this: You could change the button's template so it's essentially wrapped in a centered StackPanel. Something like this:
<Button Content="Back">
<Button.Template>
<ControlTemplate>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="{TemplateBinding Content}"></Button>
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
Or you could add a style to app.xaml (or any other place where you're storing your global styles) like this:
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Style="{x:Null}" Content="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type Button}} }" FontWeight="Bold" Padding="5"></Button>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Note that it's important to include the Style="{x:Null}" attribute on the button within the template if adding to the global styles, otherwise you'll get an infinite loop when it comes to rendering the button.

Resources